package com.zmn.oms.zmn.business.impl.work.masterwork;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.github.ltsopensource.core.domain.Job;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zmn.account.common.constant.AccountConsts;
import com.zmn.account.common.constant.IdentityConsts;
import com.zmn.account.common.dto.account.AccountInfoDIO;
import com.zmn.account.common.dto.account.AccountInfoDRO;
import com.zmn.account.dubbo.interfaces.account.AccountListRemoteService;
import com.zmn.base.common.data.common.dro.fault.FaultDRO;
import com.zmn.base.common.data.common.dro.tags.TagsDRO;
import com.zmn.base.common.data.common.query.tags.TagsQuery;
import com.zmn.base.common.data.dubbo.interfaces.fault.FaultListRemoteService;
import com.zmn.base.common.data.dubbo.interfaces.marketing.shop.MarketingShopListRemoteService;
import com.zmn.base.common.data.dubbo.interfaces.tags.TagsListRemoteService;
import com.zmn.base.engineer.common.dro.foreign.engineer.ForeignEngineerDetailInfoDRO;
import com.zmn.base.engineer.dubbo.interfaces.foreign.EngineerListRemoteService;
import com.zmn.base.pilot.common.dto.pilot.PilotCheckQuery;
import com.zmn.base.pilot.common.enums.PilotTypeEnum;
import com.zmn.base.pilot.dubbo.interfaces.pilot.PilotRemoteService;
import com.zmn.base.price.common.constant.WarrantyConst;
import com.zmn.base.price.common.dto.item.ItemWarrantyDetailDRO;
import com.zmn.base.price.dubbo.interfaces.item.ItemWarrantyRemoteService;
import com.zmn.base.product.dubbo.interfaces.product.foreign.ProductForeignListRemoteService;
import com.zmn.biz.abnormal.common.dio.AbnorAbnormalDIO;
import com.zmn.biz.abnormal.dubbo.interfaces.AbnormalModifyRemoteService;
import com.zmn.biz.engineer.common.dro.discount.EngineerDiscountDRO;
import com.zmn.biz.engineer.dubbo.interfaces.discount.EngineerDiscountListRemoteService;
import com.zmn.ccb.common.model.number.NumberDRO;
import com.zmn.ccb.dubbo.interfaces.number.NumberListRemoteService;
import com.zmn.ccc.common.enums.CallTypeEnum;
import com.zmn.ccc.common.model.record.CdrRecordDRO;
import com.zmn.ccc.dubbo.interfaces.record.RecordRemoteService;
import com.zmn.coa.dubbo.impl.interfaces.order.discount.OrderDiscountRemoteService;
import com.zmn.common.constant.OrderGlobalConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.encode.EncodeUtil;
import com.zmn.common.utils.math.MathUtil;
import com.zmn.common.utils.math.MoneyUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.dms.common.dto.coup.dio.coupon.CoupOnceCardCheckDIO;
import com.zmn.dms.common.dto.coup.dro.coupon.CoupOnceCardOnBaseDRO;
import com.zmn.dms.common.enums.DiscountTypeEnums;
import com.zmn.dms.dubbo.interfaces.coup.coupon.CoupOnceCardRemoteService;
import com.zmn.manager.lts.interfaces.task.TaskManager;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.manager.redis.RedisManager;
import com.zmn.manager.redis.lock.DistributedLock;
import com.zmn.manager.redis.lock.DistributedLockUtils;
import com.zmn.oms.business.impl.conf.attachment.ConfOrderAttachmentBServiceImpl;
import com.zmn.oms.business.interfaces.attachment.AttachmentBService;
import com.zmn.oms.business.interfaces.base.BaseCodeService;
import com.zmn.oms.business.interfaces.callpop.CallRecordBService;
import com.zmn.oms.business.interfaces.conf.channel.ConfOrderChannelBService;
import com.zmn.oms.business.interfaces.masternotice.MasterNoticeHistoryBService;
import com.zmn.oms.business.interfaces.masterphoto.OrderPhotoBService;
import com.zmn.oms.business.interfaces.masterworking.MasterWorkingBService;
import com.zmn.oms.business.interfaces.member.OrderMemberBService;
import com.zmn.oms.business.interfaces.messageV1.app.MessageSendAppService;
import com.zmn.oms.business.interfaces.messageV1.common.MessageGetSendInfoService;
import com.zmn.oms.business.interfaces.mq.MqProviderService;
import com.zmn.oms.business.interfaces.orderamount.OrderAmountCalcBService;
import com.zmn.oms.business.interfaces.orderamount.OrderDiscountCalcBService;
import com.zmn.oms.business.interfaces.orderstock.OrderStockBService;
import com.zmn.oms.business.interfaces.remark.OrderRemarkBService;
import com.zmn.oms.business.interfaces.servtype.ServItemBService;
import com.zmn.oms.business.interfaces.track.OrderTrackBService;
import com.zmn.oms.business.interfaces.warranty.OrderWarrantyBService;
import com.zmn.oms.business.interfaces.work.OrderWorkAmountBService;
import com.zmn.oms.business.interfaces.work.OrderWorkProgrammeBService;
import com.zmn.oms.business.interfaces.work.masterwork.MasterWorkBService;
import com.zmn.oms.business.interfaces.xno.OrderXnoBindBService;
import com.zmn.oms.business.interfaces.yeyxplus.YeyxPlusBService;
import com.zmn.oms.common.annotation.OrderWorkCasOperate;
import com.zmn.oms.common.annotation.ZsNormalOrderWorkLog;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.dio.quotation3.ArtificialPromDRO;
import com.zmn.oms.common.dro.PayChannelDRO;
import com.zmn.oms.common.dro.attachment.WorkAttachmentDRO;
import com.zmn.oms.common.dro.conf.channel.ConfOrderChannelDRO;
import com.zmn.oms.common.dro.orderpay.OrderPayResultDRO;
import com.zmn.oms.common.dto.MapDTO;
import com.zmn.oms.common.dto.OmsOperator;
import com.zmn.oms.common.enums.WallTypeEnum;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.common.vo.KVDict;
import com.zmn.oms.constant.MessageQueueTopicConstant;
import com.zmn.oms.manager.utils.TaskConsts;
import com.zmn.oms.model.bo.orderamount.OrderAmountCalcBO;
import com.zmn.oms.model.bo.orderamount.ReCalcOrderAmountDIO;
import com.zmn.oms.model.dto.log.CallRecordLogDTO;
import com.zmn.oms.model.dto.member.OrderMemberMasterReviewDTO;
import com.zmn.oms.model.dto.orderstock.ReleaseStockDTO;
import com.zmn.oms.model.dto.remark.OrderRemarkDTO;
import com.zmn.oms.model.dto.remark.OrderRemarkDetailDTO;
import com.zmn.oms.model.dto.serviceitem.AddOrderServiceItemDTO;
import com.zmn.oms.model.dto.track.OrderTrackDTO;
import com.zmn.oms.model.dto.track.OrderTrackDetailDTO;
import com.zmn.oms.model.dto.warranty.MasterWorkWarrantyDTO;
import com.zmn.oms.model.dto.work.WorkChannelInfoDRO;
import com.zmn.oms.model.dto.work.masterwork.*;
import com.zmn.oms.model.dto.work.modify.ArtificialPromQueryDTO;
import com.zmn.oms.model.dto.work.modify.OrderCompleteReviewDTO;
import com.zmn.oms.model.dto.work.modify.OrderDistributeDTO;
import com.zmn.oms.model.dto.work.modify.OrderWarrantyDTO;
import com.zmn.oms.model.dto.work.modify.amount.ZsDiscountDTO;
import com.zmn.oms.model.dto.work.modify.must.ZsCancelDTO;
import com.zmn.oms.model.dto.work.modify.must.ZsPartDTO;
import com.zmn.oms.model.dto.work.xno.XnoUnBindDTO;
import com.zmn.oms.model.entity.changerecord.OrderChangeRecord;
import com.zmn.oms.model.entity.conf.attachment.ConfOrderAttachment;
import com.zmn.oms.model.entity.conf.orderduty.OrderDuty;
import com.zmn.oms.model.entity.conf.orderduty.OrderDutyQuery;
import com.zmn.oms.model.entity.detail.OrderDetail;
import com.zmn.oms.model.entity.discount.OrderDiscount;
import com.zmn.oms.model.entity.masterworking.MasterWorking;
import com.zmn.oms.model.entity.member.OrderMember;
import com.zmn.oms.model.entity.operation.OrderOperation;
import com.zmn.oms.model.entity.order.OrderExtend;
import com.zmn.oms.model.entity.order.OrderFinalPrice;
import com.zmn.oms.model.entity.orderappbind.OrderThirdAppBind;
import com.zmn.oms.model.entity.orderattachment.OrderAttachment;
import com.zmn.oms.model.entity.orderattachment.OrderAttachmentQuery;
import com.zmn.oms.model.entity.pay.OrderPay;
import com.zmn.oms.model.entity.product.OrderProduct;
import com.zmn.oms.model.entity.product.OrderProductExtend;
import com.zmn.oms.model.entity.quotation3.OrderFault;
import com.zmn.oms.model.entity.quotation3.OrderQuotationProcess;
import com.zmn.oms.model.entity.serviceitem.OrderServiceItem;
import com.zmn.oms.model.entity.shop.OrderExternalShop;
import com.zmn.oms.model.entity.wallquotation.WallQuotation;
import com.zmn.oms.model.entity.warranty.OrderWarranty;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.entity.work.OrderWorkPosition;
import com.zmn.oms.model.entity.work.OrderWorkQuery;
import com.zmn.oms.model.vo.serviceitem.ServiceItemVO;
import com.zmn.oms.model.vo.warranty.WarrantyUserVO;
import com.zmn.oms.model.vo.work.DistributeVO;
import com.zmn.oms.model.vo.work.OperatePermissionVO;
import com.zmn.oms.services.interfaces.changerecord.OrderChangeRecordService;
import com.zmn.oms.services.interfaces.conf.orderduty.OrderDutyService;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.discount.OrderDiscountService;
import com.zmn.oms.services.interfaces.masterworking.MasterWorkingService;
import com.zmn.oms.services.interfaces.member.OrderMemberService;
import com.zmn.oms.services.interfaces.operation.OrderOperationService;
import com.zmn.oms.services.interfaces.order.OrderExtendService;
import com.zmn.oms.services.interfaces.order.OrderFinalPriceService;
import com.zmn.oms.services.interfaces.orderattachment.OrderAttachmentService;
import com.zmn.oms.services.interfaces.orderpay.AccountPayBService;
import com.zmn.oms.services.interfaces.pay.OrderPayService;
import com.zmn.oms.services.interfaces.product.OrderProductExtendService;
import com.zmn.oms.services.interfaces.product.OrderProductService;
import com.zmn.oms.services.interfaces.quotation3.OrderFaultService;
import com.zmn.oms.services.interfaces.quotation3.OrderQuotationProcessService;
import com.zmn.oms.services.interfaces.serviceitem.OrderServiceItemService;
import com.zmn.oms.services.interfaces.shop.OrderExternalShopService;
import com.zmn.oms.services.interfaces.wallquotation.WallQuotationService;
import com.zmn.oms.services.interfaces.warranty.OrderWarrantyService;
import com.zmn.oms.services.interfaces.work.OrderWorkPositionService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.services.interfaces.work.masterwork.MasterWorkService;
import com.zmn.oms.third.shunfeng.service.ShunfengService;
import com.zmn.oms.third.yunding.service.YundingService;
import com.zmn.oms.third.zhimi.ZhimiConsts;
import com.zmn.oms.third.zhimi.entity.ZhimiOrderExtend;
import com.zmn.oms.third.zhimi.service.ZhimiOrderExtendService;
import com.zmn.oms.zmn.business.interfaces.orderpay.OrderPayChannelBService;
import com.zmn.oms.zmn.business.interfaces.pay.OrderPayBService;
import com.zmn.oms.zmn.business.interfaces.statement.ZsOrderStatementBService;
import com.zmn.oms.zmn.business.interfaces.wallquotation.WallQuotationBService;
import com.zmn.oms.zmn.business.interfaces.warranty.ZsOrderWarrantyBService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkOperatePermissionBService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkQueryBService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkScheduleBService;
import com.zmn.oms.zmn.business.interfaces.work.customwork.ZsCustomWorkBService;
import com.zmn.oms.zmn.business.interfaces.work.customwork.ZsDistributeWorkBService;
import com.zmn.oms.zmn.business.interfaces.work.masterwork.ZsMasterWorkBService;
import com.zmn.oms.zmn.business.interfaces.work.orderpay.ZsOrderPayBService;
import com.zmn.oms.zmn.normal.business.interfaces.discount.ZsNormalOrderDiscountBService;
import com.zmn.oms.zmn.normal.business.interfaces.part.ZsNormalOrderPartBService;
import com.zmn.oms.zmn.normal.business.interfaces.serviceitem.ZsNormalOrderServiceItemBService;
import com.zmn.oms.zmn.normal.business.interfaces.work.ZsNormalWorkBService;
import com.zmn.pay.common.constant.PayConsts;
import com.zmn.performance.common.enums.OrderTimeoutTypeEnum;
import com.zmn.performance.dubbo.interfaces.order.OrderTimeoutWarningListRemoteService;
import com.zmn.saas.dubbo.constant.SaasDubboConsts;
import com.zmn.saas.dubbo.interfaces.quotation.QuotationListRemoteService;
import com.zmn.track.common.constant.TrackConfigConsts;
import com.zmn.track.common.constant.TrackConsts;
import com.zmn.track.dubbo.dto.CompleteTrackDIO;
import com.zmn.track.dubbo.dto.TrackWorkDRO;
import com.zmn.track.dubbo.dto.TrackWorkQuery;
import com.zmn.track.dubbo.dto.UpdateTrackRemarkDIO;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkListRemoteService;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkModifyRemoteService;
import com.zmn.uuc.dubbo.interfaces.user.UserThirdListRemoteService;
import io.shardingsphere.api.HintManager;
import lombok.val;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类描述：工程师工单业务实现
 *
 * @author heciqi
 * @date 2018/11/02 21:02
 */
@Service
public class ZsMasterWorkBServiceImpl implements ZsMasterWorkBService {

    private static final String TAG = "查询400呼叫号码";

    private Logger logger = LoggerFactory.getLogger(ZsMasterWorkBServiceImpl.class);

    @Autowired
    MasterWorkBService masterWorkBService;
    @Autowired
    OrderWorkService orderWorkService;
    @Autowired
    ZsOrderWorkQueryBService zsOrderWorkQueryBService;
    @Autowired
    MasterWorkService masterWorkService;
    @Autowired
    OrderWarrantyService orderWarrantyService;
    @Autowired
    OrderDetailService orderDetailService;
    @Autowired
    ZsOrderWorkOperatePermissionBService orderWorkOperatePermissionBService;
    @Autowired
    OrderTrackBService orderTrackBService;
    @Autowired
    TaskManager taskManager;
    @Autowired
    OrderServiceItemService orderServiceItemService;
    @Autowired
    OrderOperationService orderOperationService;
    @Autowired
    OrderProductExtendService orderProductExtendService;
    @Autowired
    OrderMemberService orderMemberService;
    @Autowired
    OrderMemberBService orderMemberBService;
    @Autowired
    ZsNormalWorkBService zsNormalWorkBService;
    @Autowired
    OrderExtendService orderExtendService;
    @Autowired
    OrderRemarkBService orderRemarkBService;
    @Autowired
    OrderProductService orderProductService;
    @Autowired
    private ZsOrderWarrantyBService zsOrderWarrantyBService;
    @Autowired
    private OrderWarrantyBService orderWarrantyBService;
    @Autowired
    private ZsNormalOrderDiscountBService zsNormalOrderDiscountBService;
    @Autowired
    private OrderDiscountService orderDiscountService;
    @Autowired
    private ZsNormalOrderServiceItemBService zsNormalOrderServiceItemBService;
    @Autowired
    private ZsNormalOrderPartBService zsNormalOrderPartBService;
    @Autowired
    private ZsOrderPayBService zsOrderPayBService;
    @Autowired
    private BaseCodeService baseCodeService;
    @Autowired
    private MasterWorkingService masterWorkingService;
    @Autowired
    private ZsCustomWorkBService zsCustomWorkBService;
    @Autowired
    private ZsDistributeWorkBService zsDistributeWorkBService;
    @Autowired
    private OrderWorkAmountBService orderWorkAmountBService;
    @Autowired
    private ZhimiOrderExtendService zhimiOrderExtendService;
    @Autowired
    private OrderXnoBindBService orderXnoBindBService;
    @Autowired
    private CallRecordBService callRecordBService;
    @Autowired
    private RedisManager redisManager;
    @Autowired
    private ZmnMQSender zmnMQSender;
    @Autowired
    private OrderAmountCalcBService orderAmountCalcBService;
    @Autowired
    private YundingService yundingService;
    @Autowired
    private ShunfengService shunfengService;
    @Autowired
    ZsOrderWorkScheduleBService zsOrderWorkScheduleBService;
    @Autowired
    private OrderPayChannelBService orderPayChannelBService;
    @Resource
    private OrderChangeRecordService orderChangeRecordService;
    @Autowired
    private OrderAttachmentService orderAttachmentService;
    @Resource
    private ConfOrderAttachmentBServiceImpl confOrderAttachmentBService;
    @Autowired
    private OrderDiscountCalcBService orderDiscountCalcBService;
    @Autowired
    private MessageSendAppService messageSendAppService;
    @Autowired
    private AccountPayBService accountPayBService;
    @Autowired
    private ZsOrderStatementBService zsOrderStatementBService;
    @Autowired
    private OrderWorkProgrammeBService orderWorkProgrammeBService;
    @Autowired
    private OrderPayBService orderPayBService;
    @Autowired
    private OrderStockBService orderStockBService;
    @Autowired
    private ServItemBService servItemBService;
    @Autowired
    private OrderQuotationProcessService orderQuotationProcessService;
    @Autowired
    private OrderPhotoBService orderPhotoBService;
    @Autowired
    private OrderWorkPositionService orderWorkPositionService;
    @Autowired
    private OrderDutyService orderDutyService;
    @Autowired
    private YeyxPlusBService yeyxPlusBService;
    @Autowired
    private OrderFaultService orderFaultService;
    @Autowired
    private OrderPayService orderPayService;
    @Autowired
    private OrderFinalPriceService orderFinalPriceService;
    @Autowired
    private WallQuotationService wallQuotationService;
    @Autowired
    private WallQuotationBService wallQuotationBService;
    @Autowired
    protected MessageGetSendInfoService messageGetSendInfoService;
    @Autowired
    private AttachmentBService attachmentBService;

    @Reference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
    private EngineerListRemoteService engineerListRemoteService;
    // @Reference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
    //private EngineerTouchModifyRemoteService engineerTouchModifyRemoteService;

    @Autowired
    private MqProviderService mqProviderService;

    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    protected ProductForeignListRemoteService productForeignListRemoteService;
    @DubboReference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    private PilotRemoteService pilotRemoteService;
    @DubboReference(version = SaasDubboConsts.INTERFACE_VERSION, check = false)
    private QuotationListRemoteService quotationListRemoteService;
    @DubboReference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
    private EngineerDiscountListRemoteService engineerDiscountListRemoteService;

    @DubboReference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    private OrderTimeoutWarningListRemoteService orderTimeoutWarningListRemoteService;
    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    private TagsListRemoteService tagsListRemoteService;
    @Reference(version = com.zmn.performance.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private OrderTimeoutWarningListRemoteService orderTimeoutWarningListService;
    @Reference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkListRemoteService trackWorkListRemoteService;
    @Reference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkModifyRemoteService trackWorkModifyRemoteService;
    @Reference(version = com.zmn.biz.abnormal.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    protected AbnormalModifyRemoteService abnormalModifyRemoteService;
    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    protected ItemWarrantyRemoteService itemWarrantyRemoteService;
    @Reference(version = com.zmn.dms.dubbo.utils.DubboConsts.INTERFACE_VERSION, check = false)
    protected CoupOnceCardRemoteService coupOnceCardRemoteService;
    @Reference(version = com.zmn.account.dubbo.utils.AccountDubboConsts.INTERFACE_VERSION, check = false)
    protected AccountListRemoteService accountListRemoteService;
    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    protected FaultListRemoteService faultListRemoteService;
    @Reference(version = com.zmn.coa.common.util.DubboConsts.INTERFACE_VERSION, check = false)
    protected OrderDiscountRemoteService orderDiscountRemoteService;
    @DubboReference(version = com.zmn.uuc.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    private UserThirdListRemoteService userThirdListRemoteService;

    @DubboReference(version = com.zmn.ccc.dubbo.interfaces.DubboConsts.INTERFACE_VERSION, check = false)
    private NumberListRemoteService numberListRemoteService;

    @DubboReference(version = com.zmn.market.dubbo.DubboConsts.INTERFACE_VERSION, check = false)
    private MarketingShopListRemoteService marketingShopListRemoteService;

    @DubboReference(version = com.zmn.ccc.dubbo.interfaces.DubboConsts.INTERFACE_VERSION, check = false)
    private RecordRemoteService recordRemoteService;

    private static final String MQ_TAG = "MQ_CHANNEL_ACCOUNT_TAG";
    @Resource
    protected ConfOrderChannelBService confOrderChannelBService;
    @Resource
    private MasterWorkingBService masterWorkingBService;

    @Resource
    private MasterNoticeHistoryBService masterNoticeHistoryBService;

    @Resource
    private OrderExternalShopService orderExternalShopService;

    // 计价器难度系数应用城市
    @NacosValue(value = "${difficult.ratio.city:0}", autoRefreshed = true)
    private List<Integer> DIFFICULT_RATIO_CITY = Lists.newArrayList();

    @NacosValue(value = "${service.order.process.tagId:14033}", autoRefreshed = true)
    private Integer serviceOrderProcessTagId;

    /**
     * 工程师接单
     *
     * @param masterTakeDTO
     */
    @Override
    public void updateMasterTake(MasterTakeDTO masterTakeDTO) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findMasterWorkDetail(masterTakeDTO.getOrderId(), masterTakeDTO.getWorkId(), masterTakeDTO.getMasterId());
        if (orderWork == null) {
            // 刷新工程师工单列表版本号
            //engineerTouchModifyRemoteService.saveEngineerWorkVersion(masterTakeDTO.getMasterId(), null);
            mqProviderService.sendEngineerWorkVersion(masterTakeDTO.getMasterId(), null);
            throw new OmsBaseException("无效的工单");
        }

        if (!Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING)) {
            // 删除无效的进行中工单
            boolean deleted = masterWorkingService.deleteMasterWorking(masterTakeDTO.getWorkId());
            if (deleted) {
                // 刷新工程师工单列表版本号
                //engineerTouchModifyRemoteService.saveEngineerWorkVersion(masterTakeDTO.getMasterId(), null);
                mqProviderService.sendEngineerWorkVersion(masterTakeDTO.getMasterId(), null);
            }

            throw new OmsBaseException(OrderFailConsts.FAIL_DATA_CHANGE_ORDER_STATUS, "工单不在进行中");
        }

        if (!Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_DISTRIBUTE)) {
            throw new OmsBaseException(OrderFailConsts.FAIL_DATA_CHANGE_ORDER_STATUS, "工单不是派单状态，不能接单");
        }

        // 家修匠服务商质保金逻辑
        this.processJxjCompanyAccount(orderWork);

        masterTakeDTO.setStatus(OrderStatusConsts.WORK_STATUS_TAKE);
        masterTakeDTO.setResultStatus(OrderStatusConsts.WORK_RESULT_DOING);
        masterWorkBService.updateMasterTake(masterTakeDTO, orderWork);

        // 分单至家修匠公司(45111)：可结算时间为首次领单时间
        if (Objects.equals(CompanyConsts.ZMN_JXJ_COMPANY_ID, orderWork.getCompanyId())) {
            zsOrderStatementBService.updateChannelStatementCanTime(masterTakeDTO.getOrderId(), masterTakeDTO.getWorkId(), orderWork.getChannelId(), orderWork.getCompanyId());
        }

        // 发送消息
        orderWorkProgrammeBService.sendOperateInfo(masterTakeDTO.getOrderId(), AppConsts.OPERATE_TYPE_TAKE);

        // 自动联系用户和上门
        this.autoContactUserAndVisit(orderWork);
    }

    /**
     * 处理家修匠服务商质保金逻辑
     *
     * @param orderWork
     */
    private void processJxjCompanyAccount(OrderWork orderWork) throws OmsBaseException {

        // 言而有信试点没开通直接返回
        if (!yeyxPlusBService.isYeyxPilot(orderWork.getCompanyId(), orderWork.getCityId(), orderWork.getMasterId())) {
            return;
        }

        // 查询服务商新人扶持单量
        Integer newManageCompanyNumber = 0;
        List<TagsDRO> numberList = baseCodeService.listBaseCodeMap(GlobalConsts.PLAT_MARK_ZMN, OrderConsts.BASE_CODE_MAP_ONE_TYPE_SUPPORT_NUMBER, null, null);
        if (CollectionUtil.isNotNullOrEmpty(numberList)) {
            // 查询服务商进行中和成功的单量
            OrderWorkQuery query = new OrderWorkQuery();
            query.setManageCompanyId(orderWork.getManageCompanyId());
            query.setWorkResultStatusList(Lists.newArrayList(OrderStatusConsts.WORK_RESULT_SUCCESS, OrderStatusConsts.WORK_RESULT_DOING));
            Integer doingSp = zsOrderWorkQueryBService.countOrderWorkByQuery(query);
            logger.info("[{}]查询服务商单量：【{}】", orderWork.getWorkId(), doingSp);
            // 如果单量小于新人扶持单量，可以领单
            if (doingSp <= numberList.get(0).getTwoTypeId()) {
                return;
            }
            newManageCompanyNumber = numberList.get(0).getTwoTypeId();
        }

        AccountInfoDIO dio = new AccountInfoDIO();
        dio.setAccountCategId(AccountConsts.ACCOUNT_CATEG_DEPOSIT);
        dio.setIdentityId(IdentityConsts.ACCOUNT_IDENTITY_ID_SERVICE_PROVIDER);
        dio.setIdentityObjectId((long) orderWork.getManageCompanyId());
        dio.setOperatorId((long) orderWork.getMasterId());
        dio.setOperator(orderWork.getMasterName());
        dio.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_MASTER);
        logger.info("[{}]查询服务商质保金入参：【{}】", orderWork.getWorkId(), JSON.toJSONString(dio));
        ResponseDTO<AccountInfoDRO> responseDTO = accountListRemoteService.getAccountInfo(dio);
        logger.info("[{}]查询服务商质保金出参：【{}】", orderWork.getWorkId(), JSON.toJSONString(responseDTO));
        if (!responseDTO.isSuccess() || Objects.isNull(responseDTO.getData())) {
            throw new OmsBaseException("查询服务商质保金账户失败");
        }
        if (NumberUtil.isNullOrZero(responseDTO.getData().getBalanceAmount())) {
            // 请完结手头工单或缴纳质保金后再进行领单操作
            throw new OmsBaseException(OmsErrorCodeConsts.ERROR_JXJ_BALANCE_CODE, String.valueOf(orderWork.getManageCompanyId()));
        }

        // 查询公共配置的工单冻结金额
        List<TagsDRO> amountList = baseCodeService.listBaseCodeMap(GlobalConsts.PLAT_MARK_ZMN, OrderConsts.BASE_CODE_MAP_ONE_TYPE_ORDER_FROZEN_AMOUNT, null, null);
        if (CollectionUtil.isNullOrEmpty(amountList) || NumberUtil.isNullOrZero(amountList.get(0).getTwoTypeId())) {
            return;
        }
        Integer orderAmount = MoneyUtil.parseToFen(amountList.get(0).getTwoTypeId().doubleValue());

        // 查询该服务商未完结单量
        OrderWorkQuery query = new OrderWorkQuery();
        query.setManageCompanyId(orderWork.getManageCompanyId());
        query.setWorkResultStatus(OrderStatusConsts.WORK_RESULT_DOING);
        // 只查询已领到-已算账
        query.setWorkStatusList(Lists.newArrayList(OrderStatusConsts.WORK_STATUS_TAKE, OrderStatusConsts.WORK_STATUS_VISIT, OrderStatusConsts.WORK_STATUS_SERVICE_COMPLETE, OrderStatusConsts.WORK_STATUS_COMPLETE, OrderStatusConsts.WORK_STATUS_CHECKOUT, OrderStatusConsts.WORK_STATUS_ACCOUNT));
        Integer doingNumber = zsOrderWorkQueryBService.countOrderWorkByQuery(query);
        logger.info("[{}]查询服务商未完结单量：【{}】", orderWork.getWorkId(), doingNumber);

        // 减去新人扶持单量的未完结
        doingNumber = doingNumber - newManageCompanyNumber;

        // 质保金/工单冻结金额 - 未完结单量
        Integer number = ((int) MathUtil.div(responseDTO.getData().getBalanceAmount(), orderAmount)) - doingNumber;
        logger.info("[{}]质保金余额[{}]，工单冻结金额[{}]，服务商未完结单量[{}]，可领单数[{}]", orderWork.getWorkId(), responseDTO.getData().getBalanceAmount(), orderAmount, doingNumber, number);
        if (number < 0) {
            // 请完结手头工单或缴纳质保金后再进行领单操作
            throw new OmsBaseException(OmsErrorCodeConsts.ERROR_JXJ_BALANCE_CODE, String.valueOf(orderWork.getManageCompanyId()));
        }
    }

    /**
     * 返修新单自动联系和上门
     *
     * @param orderWork
     */
    private void autoContactUserAndVisit(OrderWork orderWork) {
        // 不是返修新单不处理
        if (!Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_NEW) || !Objects.equals(orderWork.getChannelId(), OrderConsts.CHANNEL_ID_PLAT_REWORK_NEW_ORDER) || NumberUtil.isNullOrZero(orderWork.getOriginalId())) {
            return;
        }
        OrderWork rework = orderWorkService.findOrderWorkByKey(orderWork.getOriginalId(), orderWork.getOriginalId());
        // 源单不是返修单返回
        if (!Objects.equals(rework.getType(), OrderConsts.ORDER_TYPE_REWORK)) {
            return;
        }
        try {
            ContactUserDTO contactUserDTO = new ContactUserDTO();
            contactUserDTO.setOrderId(orderWork.getOrderId());
            contactUserDTO.setWorkId(orderWork.getWorkId());
            contactUserDTO.setMasterId(orderWork.getMasterId());
            contactUserDTO.setCallTime(DateUtil.getNow());

            contactUserDTO.setOperator(orderWork.getMasterName());
            contactUserDTO.setOperatorId((long) orderWork.getMasterId());
            contactUserDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_MASTER);
            this.saveContactUserTime(contactUserDTO);
        } catch (OmsBaseException e) {
            logger.info("[{}]自动联系用户失败:【{}】", orderWork.getOrderId(), e.getMessage());
            e.printStackTrace();
            return;
        }

        try {
            MasterVisitDTO masterVisitDTO = new MasterVisitDTO();
            masterVisitDTO.setOrderId(orderWork.getOrderId());
            masterVisitDTO.setWorkId(orderWork.getWorkId());
            masterVisitDTO.setMasterId(orderWork.getMasterId());

            masterVisitDTO.setOperator(orderWork.getMasterName());
            masterVisitDTO.setOperatorId((long) orderWork.getMasterId());
            masterVisitDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_MASTER);
            masterVisitDTO.setSkipVerify(true);
            this.updateMasterVisit(masterVisitDTO);
        } catch (OmsBaseException e) {
            logger.info("[{}]自动上门失败:【{}】", orderWork.getOrderId(), e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 工程师出发
     *
     * @param masterLevaeDTO
     * @return
     * @throws Exception
     */
    @Override
    public WorkDetailDTO updateMasterLeave(MasterLeaveDTO masterLevaeDTO) throws OmsBaseException {
        masterWorkBService.updateMasterLeave(masterLevaeDTO);

        WorkDetailDTO workDetailDTO = this.getWorkDetail(masterLevaeDTO.getPlat(), masterLevaeDTO.getOrderId(), masterLevaeDTO.getWorkId(), masterLevaeDTO.getMasterId(), masterLevaeDTO.getAgent());

        return workDetailDTO;
    }

    /**
     * 工程师上门
     *
     * @param masterVisitDTO
     */
    @Override
    public MasterVisitResponseDTO updateMasterVisit(MasterVisitDTO masterVisitDTO) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findMasterWorkDetail(masterVisitDTO.getOrderId(), masterVisitDTO.getWorkId(), masterVisitDTO.getMasterId());


        // 判断是否为墙面订单
//        Boolean isWallOrder = wallQuotationBService.isWallOrder(PilotCheckQuery.builder()
//                .categId(orderWork.getShowCategId())
//                .channelId(orderWork.getChannelId())
//                .cityId(orderWork.getCityId())
//                .servCategId(orderWork.getServCategId())
//                .pilotTypeId(PilotTypeEnum.WALL_QUOTE.getId())
//                .build(), orderWork.getProductGroupId(), orderWork.getServItemType());

        if (orderWork == null) {
            throw new OmsBaseException(OrderFailConsts.FAIL_DATA_CHANGE_ORDER_NOMASTER, "无效的工单");
        }

        // 必须有预约时间才能上门
        if (orderWork.getDutyTime() == null) {
            throw new OmsBaseException("必须有预约时间才能上门");
        }

        // 上门扫码
     /*   if (NumberUtil.isNullOrZero(orderWork.getVisitUserId())) {
            MasterVisitQrDTO visitQrDTO = BeanMapper.map(masterVisitDTO, MasterVisitQrDTO.class);
            visitQrDTO.setOrderId(masterVisitDTO.getOrderId());
            visitQrDTO.setWorkId(masterVisitDTO.getOrderId());
            masterWorkBService.visitUserQrCode(visitQrDTO);
        }*/

        // 上门
        masterVisitDTO.setStatus(OrderStatusConsts.WORK_STATUS_VISIT);
        masterVisitDTO.setResultStatus(OrderStatusConsts.WORK_RESULT_DOING);
        MasterVisitResponseDTO responseDTO = masterWorkBService.updateMasterVisit(masterVisitDTO, orderWork);

        // 计算和更新工单金额，迟到补偿应用
        try {
            // 是否存在迟到补偿优惠活动id
            boolean existsActivityId = NumberUtil.isNotNullOrZero(orderWork.getDiscountActivityId());
            if (NumberUtil.isNotNullOrZero(orderWork.getOriginalAmount()) && existsActivityId) {
                boolean late = this.checkLateWaring(orderWork.getOrderId());
                if (late) {
                    ReCalcOrderAmountDIO calcOrderAmountDIO = orderAmountCalcBService.getReCalcOrderAmountDIO(orderWork);
                    OrderAmountCalcBO orderAmountCalcBO = orderAmountCalcBService.reCalcOrderAmountAndDiscountAmount(TriggerAmountChangeEnum.MASTER_VISIT, calcOrderAmountDIO, null);
                    orderWorkAmountBService.updateAmountAndDiscount(orderAmountCalcBO, orderWork);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        // 发送消息
        orderWorkProgrammeBService.sendOperateInfo(masterVisitDTO.getOrderId(), AppConsts.OPERATE_TYPE_VISIT);

        // 判断上门距离与扫码（工单）距离 大于2KM接入异常工单
        this.addAbnormalOrder(masterVisitDTO, orderWork);

        return responseDTO;
    }

    private void addAbnormalOrder(OmsOperator operator, OrderWork orderWork) {
        if (NumberUtil.isNullOrZero(operator.getLatitude()) || NumberUtil.isNullOrZero(operator.getLongitude())) {
            return;
        }
        OrderWorkPosition position = orderWorkPositionService.findById(orderWork.getWorkId());

        Double latitude = position.getOrderLatitude();
        Double longitude = position.getOrderLongitude();

        double distance = MathUtil.GetDistance(operator.getLatitude(), operator.getLongitude(), latitude, longitude);
        if (distance > 2000) {
            AbnorAbnormalDIO abnorAbnormalDIO = new AbnorAbnormalDIO();
            abnorAbnormalDIO.setOrderId(orderWork.getOrderId());
            abnorAbnormalDIO.setEngineerId(orderWork.getMasterId());
            abnorAbnormalDIO.setOperator(operator.getOperator());
            abnorAbnormalDIO.setOperatorId(operator.getOperatorId().intValue());
            abnorAbnormalDIO.setOperatorMobile(operator.getOperatorMobile());
            ResponseDTO responseDTO = abnormalModifyRemoteService.addAbnormalShamComeDoor(abnorAbnormalDIO);
            logger.info("工程师上门位置与订单位置距离[{}]大于2KM ,添加异常工单 入参：{} 出参:{}", distance, JSON.toJSONString(abnorAbnormalDIO), JSON.toJSONString(responseDTO));
        }
    }

    public static void main(String[] args) {

        double distance = MathUtil.GetDistance(29.675041d, 106.514204d, 29.673410d, 106.495160d);

        System.out.println(distance);

        double realdistance = MathUtil.GetDistance(29.675041d, 106.514204d, 29.673410d, 106.495160d);
        System.out.println(((Long) Math.round(realdistance)).intValue());
        System.out.println(String.format("%.2f KM，", distance / 1000));
    }

    /**
     * 改价格
     *
     * @param changePriceDTO
     */
    @Override
    public void updatePrice(ChangePriceDTO changePriceDTO) throws OmsBaseException {
        masterWorkBService.updatePrice(changePriceDTO);
    }

    /**
     * 标记为使用配件
     *
     * @param usePartDTO
     */
    @Override
    public void updateUsePart(UsePartDTO usePartDTO) throws OmsBaseException {
        masterWorkBService.updateUsePart(usePartDTO);
    }

    /**
     * 优惠
     *
     * @param discountDTO
     */
    @Override
    public void saveDiscount(ZsDiscountDTO discountDTO) throws OmsBaseException {
        if (discountDTO.getDiscountAmount() == 0) {
            discountDTO.setRemoveDiscount(GlobalConsts.YES);
        } else {
            discountDTO.setRemoveDiscount(GlobalConsts.NO);
        }

        zsNormalOrderDiscountBService.saveArtificialMaster(discountDTO);

        // 发送优惠审核通知
        OrderWork orderWork = orderWorkService.findMasterWorkDetail(discountDTO.getOrderId(), discountDTO.getWorkId(), discountDTO.getMasterId());
        Map<String, Object> params = Maps.newHashMap();
        params.put("order_id", String.valueOf(orderWork.getOrderId()));
        params.put("work_id", String.valueOf(orderWork.getWorkId()));
        params.put("biz_type", String.valueOf(orderWork.getBizType()));
        messageSendAppService.pushAppMessageInfo(MessageRuleIdConsts.PUSH_MSG_RULEID_APPLY_COUPON, JSON.toJSONString(params), orderWork);
    }

    /**
     * 修改纸质保单号
     *
     * @param manualCodeDTO
     */
    @Override
    public void updateManualCode(ManualCodeDTO manualCodeDTO) throws OmsBaseException {
        masterWorkBService.updateManualCode(manualCodeDTO);
    }

    /**
     * 修改工程师备注
     *
     * @param masterRemarkDTO
     */
    @Override
    public boolean updateMasterRemark(MasterRemarkDTO masterRemarkDTO) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findMasterWorkDetail(masterRemarkDTO.getOrderId(), masterRemarkDTO.getWorkId(), masterRemarkDTO.getMasterId());
        if (orderWork == null) {
            throw new OmsBaseException(OrderFailConsts.FAIL_DATA_CHANGE_ORDER_NOMASTER, "无效的工单");
        }

        // 判断订单状态：只有已领单、已上门&&进行中的可以修改
        boolean status = !Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_TAKE);
        boolean resultStatus = Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_VISIT) && Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING);
        if (status && !resultStatus) {
            throw new OmsBaseException(OrderFailConsts.FAIL_DATA_CHANGE_ORDER_NOMASTER, "无效的工单");
        }

        // 返回是否需要刷新工单列表
        boolean refreshWorkList = false;

        // 发票信息
        if (StringUtil.isNotBlank(masterRemarkDTO.getInvoiceInfo())) {
            masterWorkBService.updateInvoiceInfo(masterRemarkDTO);
        }

        // 发票图片
        if (StringUtil.isNotBlank(masterRemarkDTO.getInvoiceUrl())) {
            logger.info("工程师修改发票图片：start");
            masterWorkBService.updateInvoicePic(masterRemarkDTO);
            logger.info("工程师修改发票图片：end");
        }

        // 跟单信息
        if (masterRemarkDTO.getWorkTrackList() != null && masterRemarkDTO.getWorkTrackList().size() > 0) {
            OrderTrackDTO orderTrackDTO = BeanMapper.map(masterRemarkDTO, OrderTrackDTO.class);
            orderTrackDTO.setComplete(GlobalConsts.NO);
            orderTrackDTO.setOperator(masterRemarkDTO.getMasterName());
            orderTrackDTO.setOperatorId((long) masterRemarkDTO.getMasterId());
            orderTrackDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_MASTER);

            List<OrderTrackDetailDTO> detailDTOList = new ArrayList<>(masterRemarkDTO.getWorkTrackList().size());
            orderTrackDTO.setDetailDTOList(detailDTOList);

            masterRemarkDTO.getWorkTrackList().forEach(workTrackDTO -> {
                OrderTrackDetailDTO orderTrackDetailDTO = new OrderTrackDetailDTO();
                orderTrackDetailDTO.setMapId(workTrackDTO.getMapId());
                orderTrackDetailDTO.setMapName(workTrackDTO.getMapName());
                orderTrackDetailDTO.setRemark(workTrackDTO.getRemark());
                orderTrackDetailDTO.setLevel(workTrackDTO.getLevel());
                detailDTOList.add(orderTrackDetailDTO);
            });

            orderTrackBService.updateTrack(orderTrackDTO);

            // 待件
            refreshWorkList = masterRemarkDTO.getWorkTrackList().stream().anyMatch(detail -> Objects.equals(detail.getMapId(), OrderConsts.ORDER_TRACT_TYPE_WAIT_PART_ID));

            // 拉修
            if (!refreshWorkList) {
                refreshWorkList = masterRemarkDTO.getWorkTrackList().stream().anyMatch(detail -> Objects.equals(detail.getMapId(), OrderConsts.ORDER_TRACT_TYPE_DELIVERY_ID));
            }

            // 待取消
            if (!refreshWorkList) {
                refreshWorkList = masterRemarkDTO.getWorkTrackList().stream().anyMatch(detail -> Objects.equals(detail.getMapId(), OrderConsts.ORDER_TRACT_TYPE_FAIL_APPLY_ID));
            }
        }

        // 工程师备注
        if (StringUtil.isNotBlank(masterRemarkDTO.getRemark())) {
            masterWorkBService.updateMasterRemark(masterRemarkDTO);
        }

        return refreshWorkList;
    }

    /**
     * 工程师用配件
     *
     * @param zsPartDTO
     */
    @Override
    public ResponseDTO updatePart(ZsPartDTO zsPartDTO) throws OmsBaseException {
        return zsNormalOrderPartBService.savePart(zsPartDTO);
    }

    /**
     * 工程师取消配件
     *
     * @param zsPartDTO
     */
    @Override
    public ResponseDTO cancelPart(ZsPartDTO zsPartDTO) throws OmsBaseException {
        return zsNormalOrderPartBService.cancelPart(zsPartDTO);
    }

    /**
     * 保修项
     *
     * @param orderWarrantyDTO
     */
    @Override
    public void updateWarranty(OrderWarrantyDTO orderWarrantyDTO) throws OmsBaseException {
        zsOrderWarrantyBService.updateWarranty(orderWarrantyDTO);
    }

    /**
     * 服务项
     *
     * @param addOrderServiceItemDTO
     */
    @Override
    public void updateServiceItem(AddOrderServiceItemDTO addOrderServiceItemDTO) throws OmsBaseException {
        zsNormalOrderServiceItemBService.saveServiceitem(addOrderServiceItemDTO);

        // 计价器3.0 生成服务项后需要生成保修信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(addOrderServiceItemDTO.getOrderId(), addOrderServiceItemDTO.getWorkId());
        if (Objects.nonNull(orderWork) && Objects.equals(orderWork.getServItemType(), OrderConsts.SERVICE_ITEM_TYPE_QUOTATION_THREE)) {
            OrderProduct orderProduct = orderProductService.listOrderProductByOrderId(addOrderServiceItemDTO.getOrderId()).get(0);
            OrderProductExtend extend = orderProductExtendService.listByOrderId(addOrderServiceItemDTO.getOrderId()).get(0);

            // 预生成保修信息
            List<Integer> serviceItemIdList = addOrderServiceItemDTO.getOrderServiceItemList().stream().map(OrderServiceItem::getServItemId).collect(Collectors.toList());
            logger.info("订单[{}]获取保修信息 入参：{} {} {} {}", addOrderServiceItemDTO.getOrderId(), orderWork.getBizType(), orderWork.getProductId(), serviceItemIdList, orderProduct.getTariffId());
            ResponseDTO<ItemWarrantyDetailDRO> warrantyInfoDROResponseDTO = itemWarrantyRemoteService.getByProductIdAndItemIdList(orderWork.getProductId(), serviceItemIdList);
            logger.info("订单[{}]获取保修信息 出参：{}", addOrderServiceItemDTO.getOrderId(), JSON.toJSONString(warrantyInfoDROResponseDTO));
            if (warrantyInfoDROResponseDTO.isSuccess()) {
                if (Objects.nonNull(warrantyInfoDROResponseDTO.getData()) && !Objects.equals(warrantyInfoDROResponseDTO.getData().getWarrantyType(), WarrantyConst.RULE_NOWARRANTY)) {
                    ItemWarrantyDetailDRO warrantyInfo = warrantyInfoDROResponseDTO.getData();

                    OrderWarrantyDTO warrantyDTO = new OrderWarrantyDTO();
                    warrantyDTO.setOrderId(addOrderServiceItemDTO.getOrderId());
                    warrantyDTO.setProductId(orderProduct.getProductId());
                    warrantyDTO.setProExtId(extend.getProExtId());
                    warrantyDTO.setProductName(orderProduct.getProductName());
                    warrantyDTO.setRuleId(warrantyInfo.getWarrantyType());

                    List<MapDTO> mapDTOList = warrantyInfo.getContentOptionList().stream()
//                            .filter(content -> Objects.equals(content.getDisabled(), true))
                            .map(content -> {
                                MapDTO map = new MapDTO();
                                map.setMapId(content.getValue());
                                map.setMapName(content.getLabel());
                                return map;
                            }).collect(Collectors.toList());
                    warrantyDTO.setFault(mapDTOList);
                    warrantyDTO.setDay(warrantyInfo.getDays().stream().mapToInt(Integer::valueOf).max().getAsInt());

                    warrantyDTO.setOperator("系统");
                    warrantyDTO.setOperatorId((long) com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
                    warrantyDTO.setOperatorType(com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_SYSTEM);

                    zsOrderWarrantyBService.createQuotation3Warranty(orderWork, warrantyDTO);
                } else {
                    logger.info("订单[{}]未获取到保修信息", addOrderServiceItemDTO.getOrderId());
                }
            }
        }
    }

    /**
     * 贴花照片
     *
     * @param orderImageDTO
     */
    @Override
    public void updateAppliqueImage(OrderImageDTO orderImageDTO) throws OmsBaseException {
        masterWorkBService.updateAppliqueImage(orderImageDTO);
    }

    /**
     * 工单照片
     *
     * @param orderImageDTO
     */
    @Override
    public void updateOrderImage(OrderImageDTO orderImageDTO) throws OmsBaseException {
        masterWorkBService.updateOrderImage(orderImageDTO);
    }

    /**
     * 工单工程师照片
     *
     * @param orderImageDTO
     */
    @Override
    public void updateMasterImage(OrderImageDTO orderImageDTO) throws OmsBaseException {
        masterWorkBService.updateMasterImage(orderImageDTO);
    }

    /**
     * 检查工程师是否有未完成进行中工单
     *
     * @param masterId
     */
    @Override
    public boolean checkWorkStatus(Integer masterId, Date startTime, Date endTime) throws OmsBaseException {
        return masterWorkBService.checkWorkStatus(masterId, startTime, endTime);
    }

    /**
     * 检查工程师是否有未完成进行中工单 (区分返回值)
     *
     * @param masterId
     */
    @Override
    public MasterWorkStatusDTO getMasterWorkStatus(Integer masterId, Date startTime, Date endTime) throws OmsBaseException {
        return masterWorkBService.getMasterWorkStatus(masterId, startTime, endTime);
    }

    /**
     * 进行中工单
     *
     * @param masterId
     */
    @Override
    public WorkListDTO getWorkingList(Integer masterId) throws OmsBaseException {
        WorkListDTO workListDTO = masterWorkBService.getWorkingList(masterId);
        return workListDTO;
    }

    /**
     * 完成工单
     *
     * @param masterId
     */
    @Override
    public WorkListDTO getCompleteWorkList(Integer plat, Integer masterId, Date startDate, Date endDate, Integer startIndex, Integer pageSize) throws OmsBaseException {
        return masterWorkBService.getCompleteWorkListFromEs(plat, masterId, startDate, endDate, startIndex, pageSize);
    }

    /**
     * 工单详情
     *
     * @param masterId
     */
    @Override
    public WorkDetailDTO getWorkDetail(Integer plat, Long orderId, Long workId, Integer masterId, Integer agent) throws OmsBaseException {
        WorkDetailDTO workDetailDTO = masterWorkBService.getWorkDetail(plat, orderId, workId, masterId, agent);

        Integer channelId = workDetailDTO.getChannelId();
        // 渠道扩展数据
        {
            // 智米-需要补充智米订单类型，师傅客户端需要该字段显示对应的输入框，补充智米指定的数据
            if (Objects.equals(ZhimiConsts.CHANNEL_ID, channelId)) {
                ZhimiOrderExtend zhimiOrderExtend = zhimiOrderExtendService.findZhimiOrderExtend(orderId, false);
                if (zhimiOrderExtend != null) {
                    workDetailDTO.setZhimiServiceType(zhimiOrderExtend.getServiceType());
                }
            }
        }

        /*优惠标志*/
        this.setWorkDetailDiscountFlag(workDetailDTO);

        // 预付全款不显示定金
        boolean fullPay = false;
        List<WorkTagDTO> tagList = workDetailDTO.getTagList();
        if (CollectionUtil.isNotNullOrEmpty(tagList)) {
            fullPay = tagList.stream().anyMatch(e -> Objects.equals(e.getTagId(), OrderTagConsts.TAG_ID_ADVANCE_PAY));
        }

        try {
            // 查询渠道是否可以收定金
            ConfOrderChannelDRO confOrderChannelDRO = confOrderChannelBService.getByChannelId(workDetailDTO.getChannelId());
            // 收取定金：1否，2是
            boolean noChargeDepositAmount = Objects.nonNull(confOrderChannelDRO) && Objects.equals(confOrderChannelDRO.getChargeDepositAmount(), GlobalConsts.NO);
            if (noChargeDepositAmount
                    // || ChannelConsts.CHANNEL_ID_NO_PAY_DEPOSIT_AMOUNT.contains(channelId)
                    || !Objects.equals(workDetailDTO.getPlatWork(), GlobalConsts.PLAT_MARK_ZMN) || Objects.equals(workDetailDTO.getBizType(), GlobalConsts.BIZ_TYPE_F) || orderPayChannelBService.onlySupportBankTransfer(workDetailDTO.getBizModeSource(), workDetailDTO.getChannelId()) || fullPay) {
                workDetailDTO.setShowDepositGate(GlobalConsts.NO);
            } else {
                workDetailDTO.setShowDepositGate(GlobalConsts.YES);
            }
        } catch (Exception ex) {
            workDetailDTO.setShowDepositGate(GlobalConsts.YES);
        }

        workDetailDTO.setShowHousingGate(GlobalConsts.NO);
        // if (Objects.equals(workDetailDTO.getServCategId(), GlobalConsts.SERV_CATEG_CLEAN) && workDetailDTO.getStatus() >= OrderStatusConsts.ORDER_STATUS_VISIT) {
        //     workDetailDTO.setShowHousingGate(GlobalConsts.YES);
        // } else {
        //     workDetailDTO.setShowHousingGate(GlobalConsts.NO);
        // }

        boolean needGuideThirdPartPay = false;
        // 渠道配置引导去第三方平台支付
        ConfOrderChannelDRO confOrderChannelDRO = confOrderChannelBService.getByChannelId(workDetailDTO.getChannelId());
        if (Objects.nonNull(confOrderChannelDRO)) {
            needGuideThirdPartPay = Objects.equals(confOrderChannelDRO.getGuideThirdPartPay(), com.zmn.common.constant.GlobalConsts.YES);
        }
        // 写死的特殊渠道
        List<PayChannelDRO> listPayChannel = orderPayChannelBService.listThirdPayChannel(workDetailDTO.getChannelId());
        // 新机销售也走扫码
        // 川南环保也是扫码
        if (needGuideThirdPartPay || CollectionUtil.isNotNullOrEmpty(listPayChannel) || ProductConsts.LIST_SPECIAL_SERV_PRODUCT_GROUP.contains(workDetailDTO.getServProductGroupId()) || !Objects.equals(workDetailDTO.getPlatWork(), GlobalConsts.PLAT_MARK_ZMN)) {
            workDetailDTO.setSpecialChannelPay(GlobalConsts.YES);
            workDetailDTO.setNeedAcceptance(GlobalConsts.NO);
        } else {
            workDetailDTO.setSpecialChannelPay(GlobalConsts.NO);
        }

        /*是否支持点评验券*/

        /*京东售后价格表*/

        // 查询可用次卡数量
        boolean isTimesCardWork = Optional.ofNullable(workDetailDTO.getOrderDiscountList()).orElse(Lists.newArrayList()).stream().anyMatch(discount -> {
            return Objects.equals(discount.getCateg(), DiscountTypeEnums.DISCOUNT_COUP_ONCECARD.getSubType());
        });
        if (!isTimesCardWork) {
            CoupOnceCardCheckDIO dio = new CoupOnceCardCheckDIO();
            dio.setUserId(workDetailDTO.getUserId());
            dio.setLongitude(new BigDecimal(String.valueOf(workDetailDTO.getLongitude())));
            dio.setLatitude(new BigDecimal(String.valueOf(workDetailDTO.getLatitude())));
            dio.setProductId(workDetailDTO.getProductList().get(0).getShowProductId());
            dio.setCityId(workDetailDTO.getCityId());
            dio.setChannelId(workDetailDTO.getChannelId());
            dio.setBizType(workDetailDTO.getBizType());
            dio.setPrice(workDetailDTO.getOriginalAmount());
            dio.setTariffOnoff(Objects.equals(workDetailDTO.getServItemType(), OrderConsts.SERVICE_ITEM_TYPE_FAULT) ? GlobalConsts.YES : GlobalConsts.NO);
            dio.setUntariffOnoff(!Objects.equals(workDetailDTO.getServItemType(), OrderConsts.SERVICE_ITEM_TYPE_FAULT) ? GlobalConsts.YES : GlobalConsts.NO);
            dio.setExtendedWarranty(workDetailDTO.getMember());
            dio.setUnExtendedWarranty(Objects.equals(workDetailDTO.getMember(), GlobalConsts.YES) ? GlobalConsts.NO : GlobalConsts.YES);
            dio.setTaximeter3(Objects.equals(workDetailDTO.getServItemType(), OrderConsts.SERVICE_ITEM_TYPE_QUOTATION_THREE) ? GlobalConsts.YES : GlobalConsts.NO);

            String limitAddress = String.format("%s%s%s%s%s", workDetailDTO.getProvinceName(), workDetailDTO.getCityName(), workDetailDTO.getCountyName(), Optional.ofNullable(workDetailDTO.getStreet()).orElse(""), workDetailDTO.getAddress());
            dio.setLimitAddress(limitAddress);

            logger.info("获取次卡信息 入参：{}", JSON.toJSONString(dio));
            ResponseDTO<List<CoupOnceCardOnBaseDRO>> responseDTO = coupOnceCardRemoteService.listCoupOnceCardBaseInfo(dio);
            logger.info("获取次卡信息 出参：{}", JSON.toJSONString(responseDTO));
            if (responseDTO.isSuccess() && CollectionUtils.isNotEmpty(responseDTO.getData())) {
                workDetailDTO.setAvailableTimesCardNum(responseDTO.getData().size());
            }
        }

        // 计价器3.0故障信息
        processWorkRepairMethod(workDetailDTO);

        // 配件使用类型
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        workDetailDTO.setPartUseType(zsNormalOrderPartBService.getPartUseType(orderWork));

        if (Objects.equals(workDetailDTO.getFinalPrice(), GlobalConsts.YES)) {
            // 下单时支付信息
            OrderFinalPrice finalPriceOrderExt = orderFinalPriceService.findByOrderIdAndWorkId(orderId, workId);
            if (Objects.nonNull(finalPriceOrderExt)) {
                workDetailDTO.setPaceanOrderPayType(finalPriceOrderExt.getPayType());
                workDetailDTO.setPaceanOrderItemTypeName(finalPriceOrderExt.getItemTypeName());
            }
        }
        // 判断是否扫码
        workDetailDTO.setAttentionWechat(true);
        if (NumberUtil.isNullOrZero(orderWork.getVisitUserId())) {
            OrderExtend orderExtend = orderExtendService.findOrderExtendByOrderId(orderWork.getOrderId());
            if (Objects.isNull(orderExtend) || NumberUtil.isNullOrZero(orderExtend.getWeChatScanUserId())) {
                workDetailDTO.setAttentionWechat(false);
            }
            orderWork.setVisitUserId(orderExtend.getWeChatScanUserId());
        }
        // 判断用户是否关注
        if (workDetailDTO.getAttentionWechat()) {
            Boolean checkAttentionWeChat = this.checkAttentionWeChat(orderWork);
            workDetailDTO.setAttentionWechat(checkAttentionWeChat);
        }

        // 图片
        String newTipSrc = masterNoticeHistoryBService.getNewTipSrc(orderWork);
        workDetailDTO.setNewTipSrc(newTipSrc);

        // 是否可以进入清洁页面
        Boolean enterCleanPage = this.enterCleanPage(orderId, workId, orderWork);
        workDetailDTO.setEnterCleanPage(enterCleanPage);

        // 是否走默认服务流程
        if (Objects.equals(orderWork.getServItemType(),OrderConsts.SERVICE_ITEM_TYPE_ORDER)){
            ResponseDTO<TagsDRO> responseDTO = tagsListRemoteService.getById(serviceOrderProcessTagId);
            if (responseDTO.isSuccess()){
                TagsDRO tagsDRO = responseDTO.getData();
                if (Objects.nonNull(tagsDRO) && Objects.equals(tagsDRO.getStatus(),GlobalConsts.YES) &&
                        NumberUtil.isNotNullOrZero(orderWork.getProductId())){
                    workDetailDTO.setServiceOrderProcess(GlobalConsts.YES);
                }
            }
        }

        // 外呼电话
        String calledNumber = this.getCalledNumber(orderId);
        if(StringUtil.isNotBlank(calledNumber)){
            workDetailDTO.setCalledNumber(calledNumber);
        }

        // 外部店铺ID
        String externalShopId = this.getExternalShopId(orderId, workId);
        if(StringUtil.isNotBlank(externalShopId)){
            workDetailDTO.setExternalShopId(externalShopId);
        }

        return workDetailDTO;
    }


    @Override
    public WorkDetailDTO getWorkDetailSrcMaster(Integer plat, Long orderId, Long workId, Integer masterId, Integer agent) throws OmsBaseException {
        try (HintManager hintManager = HintManager.getInstance()) {
            hintManager.setMasterRouteOnly();
            return this.getWorkDetail(plat, orderId, workId, masterId, agent);
        }
    }

    /**
     * 工单简版详情
     */
    @Override
    public WorkDetailDTO getWorkSimpleDetail(Integer plat, Long orderId, Long workId) throws OmsBaseException {
        WorkDetailDTO workDetailDTO = masterWorkBService.getWorkSimpleDetail(plat, orderId, workId);
        return workDetailDTO;
    }

    /**
     * 历史工单详情
     *
     * @param masterId
     */
    @Override
    public WorkDetailDTO getHisWorkDetail(Integer plat, Long orderId, Long workId, Integer masterId, Integer agent) throws OmsBaseException {
        WorkDetailDTO workDetailDTO = masterWorkBService.getHisWorkDetail(plat, orderId, workId, masterId, agent);
        return workDetailDTO;
    }

    /**
     * 检查工单优惠状态
     */
    @Override
    public void checkDiscountStatus(Long orderId, Long workId, Integer masterId) throws OmsBaseException {
        /*优惠标志*/
        OperatePermissionVO permissionDiscount = orderWorkOperatePermissionBService.getOperatePermission(orderId, workId, OrderConsts.ORDER_OP_TYPE_DISCOUNT_LEVEL_ONE);
        if (!permissionDiscount.getCanOperate()) {
            throw new OmsBaseException(permissionDiscount.getMsg());
        }
    }

    /**
     * 是否需要完成码
     *
     * @param workId
     */
    @Override
    public Boolean needCompleteCode(Long orderId, Long workId) {

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        // 天猫不需要完成码
        if (ChannelConsts.CHANNEL_ID_NOSUPPORT_ACCOUNT_PAY.contains(orderWork.getChannelId())) {
            return false;
        }

        String redisKey = String.format(RedisKeyConsts.ORDER_SERVICE_COMPLETE_KEY, workId);
        return Objects.equals(orderWork.getBizType(), GlobalConsts.BIZ_TYPE_F) && !redisManager.exists(redisKey);
    }

    /**
     * 工单服务完成
     *
     * @param serviceCompleteDIO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_SERVICE_COMPLETE, beforeProceed = false)
    public void serviceComplete(ServiceCompleteDIO serviceCompleteDIO) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(serviceCompleteDIO.getOrderId(), serviceCompleteDIO.getWorkId());

        /*优惠标志*/
        OperatePermissionVO permissionDiscount = orderWorkOperatePermissionBService.getOperatePermission(serviceCompleteDIO.getOrderId(), serviceCompleteDIO.getWorkId(), OrderConsts.ORDER_OP_TYPE_SERVICE_COMPLETE, com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_MASTER);
        if (!permissionDiscount.getCanOperate()) {
            throw new OmsBaseException(permissionDiscount.getMsg());
        }

        // 判断是否有这个key
        boolean needCompleteCode = needCompleteCode(serviceCompleteDIO.getOrderId(), serviceCompleteDIO.getWorkId());

        if (needCompleteCode && Objects.isNull(serviceCompleteDIO.getCompleteCode())) {
            throw new OmsBaseException("请输入完成码");
        }

        if (!Objects.equals(orderWork.getChannelId(), 10133) && needCompleteCode) {
            this.verifyCompleteCode(serviceCompleteDIO.getOrderId(), serviceCompleteDIO.getWorkId(), serviceCompleteDIO.getCompleteCode());
        }

        // 工单状态变为服务完成
        OrderWork updateOrderWork = new OrderWork();
        updateOrderWork.setOrderId(serviceCompleteDIO.getOrderId());
        updateOrderWork.setWorkId(serviceCompleteDIO.getWorkId());
        // 无上门时间，塞预约时间
        if (Objects.isNull(orderWork.getVisitTime())) {
            updateOrderWork.setVisitTime(Optional.ofNullable(orderWork.getDutyTime()).orElse(DateUtil.getNow()));
        }
        updateOrderWork.setStatus(OrderStatusConsts.WORK_STATUS_SERVICE_COMPLETE);
        updateOrderWork.setServiceCompleterId(serviceCompleteDIO.getOperatorId());
        updateOrderWork.setServiceCompleteTime(DateUtil.getNow());
        updateOrderWork.setServiceCompleteReviewStatus(OrderConsts.REVIEW_STATUS_DOING);
        updateOrderWork.setUpdater(serviceCompleteDIO.getOperator());
        masterWorkService.updateServiceComplete(updateOrderWork);

        // 更新师傅进行中表
        MasterWorking masterWorking = new MasterWorking();
        masterWorking.setWorkId(serviceCompleteDIO.getWorkId());
        masterWorking.setServiceCompleteReviewStatus(OrderConsts.REVIEW_STATUS_DOING);
        masterWorking.setStatus(OrderStatusConsts.WORK_STATUS_SERVICE_COMPLETE);
        masterWorkingService.updateMasterWorking(masterWorking);

    }


    /**
     * 工单服务完成审核
     *
     * @param orderCompleteReviewDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_SERVICE_COMPLETE_REVIEW, beforeProceed = false)
    public void saveCompleteReview(OrderCompleteReviewDTO orderCompleteReviewDTO) throws OmsBaseException {

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderCompleteReviewDTO.getOrderId(), orderCompleteReviewDTO.getWorkId());
        // 如果资金账户金额不够，则不可：审核成功
        if (Objects.equals(orderCompleteReviewDTO.getServiceCompleteReviewStatus(), OrderConsts.REVIEW_STATUS_SUCCESS)) {
            accountPayBService.checkAccount(orderCompleteReviewDTO.getOrderId(), orderWork.getOriginalAmount());
        }

        // 修改服务项内部价
        List<ServiceItemVO> serviceItemVOS = orderCompleteReviewDTO.getServiceItemVOList();
        if (CollectionUtil.isNotNullOrEmpty(serviceItemVOS)) {
            serviceItemVOS.forEach(item -> {
                OrderServiceItem serviceItem = new OrderServiceItem();
                serviceItem.setOrderId(orderCompleteReviewDTO.getOrderId());
                serviceItem.setServItemId(item.getServItemId());
                serviceItem.setInternalSettlementPrice(item.getInternalSettlementPrice());
                serviceItem.setInternalTotalPrice(item.getInternalTotalPrice());
                orderServiceItemService.updateInternalPriceByKey(serviceItem);
            });
        }

        // 保存审核结果
        OrderWork updateOrderWork = BeanMapper.map(orderCompleteReviewDTO, OrderWork.class);
        if (Objects.equals(orderCompleteReviewDTO.getServiceCompleteReviewStatus(), OrderConsts.REVIEW_STATUS_FAIL)) {
            // 审核失败工单状态变为已上门
            updateOrderWork.setStatus(OrderStatusConsts.WORK_STATUS_VISIT);
            updateOrderWork.setServiceCompleteTime(null);
            orderCompleteReviewDTO.setStatus(OrderStatusConsts.WORK_STATUS_VISIT);
        }
        updateOrderWork.setServiceCompleteReviewTime(new Date());
        masterWorkService.updateServiceComplete(updateOrderWork);

        // 同步审核状态到师傅进行中表
        MasterWorking masterWorking = new MasterWorking();
        masterWorking.setWorkId(orderWork.getWorkId());
        masterWorking.setServiceCompleteReviewStatus(orderCompleteReviewDTO.getServiceCompleteReviewStatus());
        masterWorkingService.updateMasterWorking(masterWorking);

        // 审核失败
        if (Objects.equals(orderCompleteReviewDTO.getServiceCompleteReviewStatus(), OrderConsts.REVIEW_STATUS_FAIL)) {
            // 处理失败原因
            OrderRemarkDTO orderRemarkDTO = new OrderRemarkDTO();
            orderRemarkDTO.setOrderId(orderCompleteReviewDTO.getOrderId());
            orderRemarkDTO.setWorkId(orderCompleteReviewDTO.getWorkId());
            orderRemarkDTO.setContent(orderCompleteReviewDTO.getContent());
            orderRemarkDTO.setOperator(orderCompleteReviewDTO.getOperator());
            orderRemarkDTO.setOperatorId(orderCompleteReviewDTO.getOperatorId());

            List<OrderRemarkDetailDTO> detailDTOList = Lists.newArrayList();
            List<KVDict<Integer>> replyVisitList = orderCompleteReviewDTO.getAuditReason();
            if (CollectionUtil.isNotNullOrEmpty(replyVisitList)) {
                replyVisitList.forEach(codeMap -> {
                    OrderRemarkDetailDTO detailDTO = new OrderRemarkDetailDTO();
                    detailDTO.setMapId(codeMap.getValue());
                    detailDTO.setMapName(codeMap.getText());
                    detailDTOList.add(detailDTO);
                });
            }
            orderRemarkDTO.setDetailDTOList(detailDTOList);
            // 保存审核失败原因
            orderRemarkBService.insertOrderRemark(orderRemarkDTO, OrderConsts.ORDER_REMARK_TYPE_REVIEW_FAIL);
            // 审核失败后，给：工程师APP发送通知，需重新确认价格后提交
            Map<String, Object> params = Maps.newHashMap();
            params.put("order_id", String.valueOf(orderWork.getOrderId()));
            params.put("work_id", String.valueOf(orderWork.getWorkId()));
            params.put("biz_type", String.valueOf(orderWork.getBizType()));
            messageSendAppService.pushAppMessageInfo(MessageRuleIdConsts.PUSH_MSG_RULEID_SERVICE_COMPLETE, JSON.toJSONString(params), orderWork);
        } else {
            // 自动完成
        }
        // 服务完成审核后刷新工程师工单列表版本号
        // engineerTouchModifyRemoteService.saveEngineerWorkVersion(orderWork.getMasterId(), null);
        mqProviderService.sendEngineerWorkVersion(orderWork.getMasterId(), null);
    }

    /**
     * 服务完成自动完成
     *
     * @param orderCompleteReviewDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_SERVICE_COMPLETE_REVIEW, beforeProceed = false)
    public void autoReviewComplete(OrderCompleteReviewDTO orderCompleteReviewDTO) {
        OrderWork orderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderCompleteReviewDTO.getOrderId(), orderCompleteReviewDTO.getWorkId());

        OrderWork updateOrderWork = new OrderWork();
        updateOrderWork.setOrderId(orderCompleteReviewDTO.getOrderId());
        updateOrderWork.setWorkId(orderCompleteReviewDTO.getWorkId());
        updateOrderWork.setStatus(OrderStatusConsts.WORK_STATUS_SERVICE_COMPLETE);
        updateOrderWork.setServiceCompleterId(orderCompleteReviewDTO.getOperatorId());
        updateOrderWork.setServiceCompleteTime(DateUtil.getNow());
        updateOrderWork.setServiceCompleteReviewStatus(OrderConsts.REVIEW_STATUS_SUCCESS);
        updateOrderWork.setUpdater(orderCompleteReviewDTO.getOperator());
        // 无上门时间，塞预约时间
        if (Objects.isNull(orderWork.getVisitTime())) {
            updateOrderWork.setVisitTime(Optional.ofNullable(orderWork.getDutyTime()).orElse(DateUtil.getNow()));
        }
        masterWorkService.updateServiceComplete(updateOrderWork);

        // 更新师傅进行中表
        MasterWorking masterWorking = new MasterWorking();
        masterWorking.setWorkId(orderCompleteReviewDTO.getWorkId());
        masterWorking.setServiceCompleteReviewStatus(OrderConsts.REVIEW_STATUS_SUCCESS);
        masterWorking.setStatus(OrderStatusConsts.WORK_STATUS_SERVICE_COMPLETE);
        masterWorkingService.updateMasterWorking(masterWorking);

        // 服务完成审核后刷新工程师工单列表版本号
        //engineerTouchModifyRemoteService.saveEngineerWorkVersion(orderCompleteReviewDTO.getMasterId(), null);
        mqProviderService.sendEngineerWorkVersion(orderCompleteReviewDTO.getMasterId(), null);
    }

    /**
     * 工单完成
     *
     * @param completeDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @OrderWorkCasOperate(type = OrderConsts.ORDER_OP_TYPE_COMPLETE)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_COMPLETE, beforeProceed = false)
    public void completeOrder(CompleteDTO completeDTO) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findOrderWorkByKeySrcMaster(completeDTO.getOrderId(), completeDTO.getWorkId());
        // 非进行中或者完成后不作处理
        if (orderWork.getResultStatus() != OrderStatusConsts.WORK_RESULT_DOING || orderWork.getStatus() >= OrderStatusConsts.WORK_STATUS_COMPLETE) {
            logger.info("[{}]工单完成，不作处理", completeDTO.getWorkId());
            return;
        }
        this.checkWarrantyPay(completeDTO, orderWork, Boolean.TRUE);

        // 工程师完成，设置现场完成状态和日志
        if (Objects.equals(completeDTO.getOperatorType(), GlobalConsts.OPERATE_USER_TYPE_MASTER)) {
            CompletePositionDTO completePosition = this.getCompletePosition(completeDTO);
            completeDTO.setCompleteOnSite(completePosition.getCompleteOnSite());
            completeDTO.setOperatorLogRemark(completePosition.getLogRemark());
        } else {
            completeDTO.setCompleteOnSite(GlobalConsts.NO);
        }

        // 1，价格为0的置为已支付
        if (orderWork.getMasterAmount() != null && orderWork.getMasterAmount() == 0) {
            completeDTO.setUpdatePayStatus(true);
        }
        completeDTO.setStatus(OrderStatusConsts.WORK_STATUS_COMPLETE);

        // C端工单需要自动补全服务完成、审核等信息
        if (Objects.equals(orderWork.getBizType(), GlobalConsts.BIZ_TYPE_C)) {
            completeDTO.setAutoServiceComplete(GlobalConsts.YES);
        }

        masterWorkBService.updateComplete(completeDTO);

        // 2，激活并领取保修卡
        logger.info("[{}]工单完成，激活并领取保修卡", completeDTO.getWorkId());
        orderWarrantyBService.activeAndTakeWarranty(completeDTO.getOrderId());

        // 3-1，支付优惠券
        logger.info("[{}]工单完成，支付优惠券", completeDTO.getWorkId());
        zsOrderPayBService.payDiscountAmount(orderWork);

        // 3-2，支付渠道预付款
        logger.info("{}工单完成，支付渠道预付款", completeDTO.getWorkId());
        try {
            zsOrderPayBService.payChannelPrepaidAmount(orderWork);
        } catch (Exception e) {
            logger.error("支付渠道预付款异常 {}", e.getMessage(), e);
            this.insertChannelPrepaidAmountPay(orderWork); // 补上支付记录
        }

        // 4，删除进行中工单，删除版本号
        boolean deleted = masterWorkingService.deleteMasterWorking(completeDTO.getWorkId());
        if (deleted) {
            logger.info("[{}]工单完成，删除版本号", completeDTO.getWorkId());
            //engineerTouchModifyRemoteService.saveEngineerWorkVersion(orderWork.getMasterId(), null);
            mqProviderService.sendEngineerWorkVersion(orderWork.getMasterId(), null);
        }

        // 5，修正金额(新单并且是保外单)
        if (Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_NEW) && Objects.equals(orderWork.getBizType(), com.zmn.consts.GlobalConsts.BIZ_TYPE_C)) {
            try {
                orderWorkAmountBService.fixedAmount(completeDTO.getOrderId(), completeDTO.getWorkId());
            } catch (Exception e) {
                logger.error("完成后修正金额异常 {}", e.getMessage(), e);
            }
        }

        // 6，添加定时评价任务
        try {
            logger.info("[{}]工单完成，添加定时评价任务", completeDTO.getOrderId());
            this.addCommentJob(completeDTO.getOrderId());
        } catch (Exception e) {
            logger.error("添加定时评价任务{}", e.getMessage(), e);
        }

        // 8，完成跟单
        orderTrackBService.completeAllTrack(orderWork.getOrderId(), orderWork.getWorkId(), "工单完成");

        // 9，移除完成码校验key
        String redisKey = String.format(RedisKeyConsts.ORDER_SERVICE_COMPLETE_KEY, String.valueOf(orderWork.getWorkId()));
        redisManager.del(redisKey);

        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(completeDTO.getOrderId());

        // 10，订单完成节点 推送渠道相关信息给ERP,需要进行渠道相关金额算账
        this.syncOrderChannelInfoToERP(completeDTO, orderWork, orderDetail);

        // 11，作废未使用的特殊优惠券
        try {
            String redisItemCodeKey = String.format(RedisKeyConsts.DISCOUNT_SPECIAL_ITEMCODE_KEY, String.valueOf(orderWork.getOrderId()));
            if (redisManager.exists(redisItemCodeKey)) {
                boolean usedSpecDiscount = false;
                if (NumberUtil.isNotNullOrZero(orderWork.getDiscountAmount())) {
                    List<OrderDiscount> orderDiscountList = orderDiscountService.listByOrderId(orderWork.getOrderId());
                    usedSpecDiscount = orderDiscountList.stream().anyMatch(e -> Objects.equals(e.getSourceId(), DiscountConsts.BATCH_ID_FREE_DISCOUNT_HQ_COMPANY) || Objects.equals(e.getSourceId(), DiscountConsts.BATCH_ID_FREE_DISCOUNT_SUB_COMPANY));
                }
                if (!usedSpecDiscount) {
                    logger.info("[{}]作废未使用的特殊优惠[{}]", orderWork.getOrderId(), redisItemCodeKey);
                    orderDiscountCalcBService.obsDiscountItemCodes(Lists.newArrayList(redisManager.get(redisItemCodeKey)), orderWork.getOrderId());
                    orderDiscountCalcBService.delRedisSpecialDiscountCoupon(orderWork.getOrderId());
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        // 12，保存节能减排能量值
        updateProductsEmissions(orderWork.getOrderId(), orderWork.getProductId());

        // 13，啄木鸟原单首次返修完成时 自动延保原单
        if (Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_REWORK) && Objects.equals(orderWork.getPlatWork(), GlobalConsts.PLAT_MARK_ZMN)) {
            zsOrderWarrantyBService.autoAddWarrantyDay(orderWork.getOrderId(), orderWork.getWorkId());
        }

        // 14，保留24小时配件申请，发队列
        if (Objects.equals(orderWork.getPartRetain(), GlobalConsts.YES)) {
            logger.info("[{}]工单完成，保留24小时配件申请任务开始", orderWork.getOrderId());
            try {
                this.addRetainPartJob(orderWork, orderWork.getCompleteTime());
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }

        // 释放库存
        ReleaseStockDTO releaseStockDTO = new ReleaseStockDTO();
        releaseStockDTO.setOrderId(orderWork.getOrderId());
        releaseStockDTO.setWorkId(orderWork.getWorkId());
        releaseStockDTO.setMasterId(orderWork.getMasterId());
        releaseStockDTO.setCityId(orderWork.getCityId());
        orderStockBService.releaseStock(releaseStockDTO);

        // 完成时取消待支付记录
        this.cancelWaitPay(orderWork);

        // 7，若绑定小号工单完成需解除绑定 -> 延迟到7天后解绑
        XnoUnBindDTO xnoUnBindDTO = new XnoUnBindDTO();
        xnoUnBindDTO.setOrderId(orderWork.getOrderId());
        xnoUnBindDTO.setWorkId(orderWork.getWorkId());
        orderXnoBindBService.sendToUnBindQueue(xnoUnBindDTO);
    }

    /**
     * 判断是否是质保金支付并且订单金额等于质保金支付金额
     *
     * @param completeDTO 保修
     * @param orderWork   订单
     * @param warranty    是否插入保修
     * @return
     */
    @Override
    public void checkWarrantyPay(CompleteDTO completeDTO, OrderWork orderWork, Boolean warranty) throws OmsBaseException {
        List<OrderPay> orderPays = orderPayService.listOrderPayByOrderId(completeDTO.getOrderId());
        Integer warrantyPaymentAmount = orderPays.stream()
                .filter(x -> Objects.equals(x.getAmountType(), OrderPayConsts.ORDER_PAY_MASTER)
                        && Objects.equals(PayConsts.PAY_TRADE_TYPE_INTIME, x.getTradeType())
                        && Objects.equals(PayConsts.PAY_CHANNEL_PLATFORM_DEPOSIT, x.getPayChannelId()))
                .mapToInt(OrderPay::getAmount).sum();

        Integer channelPrepayAmount = Optional.ofNullable(orderWork.getChannelPrepayAmount()).orElse(0);
        Integer prepayAmount = Optional.ofNullable(orderWork.getPrepayAmount()).orElse(0);
        Integer depositAmount = Optional.ofNullable(orderWork.getDepositAmount()).orElse(0);
        Integer masterAmount = Optional.ofNullable(orderWork.getMasterAmount()).orElse(0);
        Integer refundAmount = Optional.ofNullable(orderWork.getRefundAmount()).orElse(0);
        Integer orderInclude = channelPrepayAmount + prepayAmount + depositAmount + masterAmount - refundAmount;
        // 判断是否是质保金支付（有质保金支付记录则为质保金支付）
        if (NumberUtil.isNullOrZero(warrantyPaymentAmount)) {
            return;
        }
        if (Objects.equals(orderWork.getTotalAmount(), orderInclude) && Boolean.TRUE.equals(warranty)) {
            WarrantyUserVO warrantyByOrderId = zsOrderWarrantyBService.findWarrantyByOrderId(orderWork.getOrderId());
            if (Objects.isNull(warrantyByOrderId)) {
                // 获取原单的服务项
                List<OrderServiceItem> orderServiceItemList = orderServiceItemService.listByOrderId(orderWork.getOrderId());
                Set<Integer> itemIds = orderServiceItemList.stream().map(OrderServiceItem::getServItemId).collect(Collectors.toSet());
                logger.info("#warranty#订单号={}, 获取保修卡延保信息入参 plat={}，product={}，itemIds={}", orderWork.getOrderId(), orderWork.getPlatWork(), orderWork.getProductId(), itemIds);
                com.zmn.common.dto2.ResponseDTO<ItemWarrantyDetailDRO> resp = itemWarrantyRemoteService.getByProductIdAndItemIdList(orderWork.getProductId(), Lists.newArrayList(itemIds));
                logger.info("#warranty#订单号={}, 获取保修卡延保信息出参 {}", orderWork.getOrderId(), JSON.toJSONString(resp));
                if (resp.isSuccess()) {
                    if (Objects.nonNull(resp.getData()) && !Objects.equals(resp.getData().getWarrantyType(), WarrantyConst.RULE_NOWARRANTY)) {
                        ItemWarrantyDetailDRO warrantyInfo = resp.getData();
                        OrderProduct orderProduct = orderProductService.listOrderProductByOrderId(orderWork.getOrderId()).get(0);
                        OrderProductExtend extend = orderProductExtendService.listByOrderId(orderWork.getOrderId()).get(0);
                        OrderWarrantyDTO warrantyDTO = new OrderWarrantyDTO();
                        warrantyDTO.setOrderId(orderWork.getOrderId());
                        warrantyDTO.setWorkId(orderWork.getWorkId());
                        warrantyDTO.setProductId(orderProduct.getProductId());
                        warrantyDTO.setProExtId(extend.getProExtId());
                        warrantyDTO.setProductName(orderProduct.getProductName());
                        warrantyDTO.setRuleId(warrantyInfo.getWarrantyType());
                        List<MapDTO> mapDTOList = warrantyInfo.getContentOptionList().stream()
                                .map(content -> {
                                    MapDTO map = new MapDTO();
                                    map.setMapId(content.getValue());
                                    map.setMapName(content.getLabel());
                                    return map;
                                }).collect(Collectors.toList());
                        warrantyDTO.setFault(mapDTOList);
                        warrantyDTO.setDay(warrantyInfo.getDays().stream().mapToInt(Integer::valueOf).max().getAsInt());

                        warrantyDTO.setOperator("系统");
                        warrantyDTO.setOperatorId((long) com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
                        warrantyDTO.setOperatorType(com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
                        zsOrderWarrantyBService.updateWarranty(warrantyDTO);
                    } else {
                        logger.info("订单[{}]未获取到保修信息", orderWork.getOrderId());
                    }
                }
            }
        } else {
            throw new OmsBaseException("质保金支付订单，请先通过修改产品、改价格、优惠等方式，使其订单收入等于收款未支付金额后再试！");
        }
    }

    /**
     * 取消待支付记录
     *
     * @param orderWork
     */
    private void cancelWaitPay(OrderWork orderWork) {
        List<OrderPay> orderPayList = orderPayService.listOrderPayByOrderIdAndWorkId(orderWork.getOrderId(), orderWork.getWorkId());
        if (CollectionUtil.isNullOrEmpty(orderPayList)) {
            return;
        }

        List<OrderPay> waitPayList = orderPayList.stream().filter(e -> Objects.equals(e.getPayStatus(), PayConsts.PAY_STATUS_NONE)).collect(Collectors.toList());
        if (CollectionUtil.isNullOrEmpty(waitPayList)) {
            return;
        }

        waitPayList.forEach(e -> {
            OrderPay orderPay = new OrderPay();
            orderPay.setOrderId(e.getOrderId());
            orderPay.setOrderPayId(e.getOrderPayId());
            orderPayService.deleteByKey(orderPay);
        });
    }

    /**
     * 添加保留配件任务
     *
     * @param orderWork
     * @param retainPartStartTime
     */
    @Override
    public void addRetainPartJob(OrderWork orderWork, Date retainPartStartTime) {

        Date completeTime = Optional.ofNullable(retainPartStartTime).orElse(DateUtil.getNow());
        int retainHour = 24;// 保留配件时间-24小时
        Date hour24ExecuteAutoAccount = DateUtil.addMinute(completeTime, 60 * retainHour);// 24小时自动算账
        Date hour12Remind = DateUtil.addMinute(completeTime, 60 * (retainHour - 12));//  剩余12小时提醒
        Date hour6Remind = DateUtil.addMinute(completeTime, 60 * (retainHour - 6));// 剩余6小时提醒

        Map<Integer, Date> taskMap = new HashMap<Integer, Date>() {{
            put(OrderPartConsts.RETAIL_PART_24HOUR_AOTUACCOUNT, hour24ExecuteAutoAccount);
            put(OrderPartConsts.RETAIL_PART_12HOUR_REMIND, hour12Remind);
            put(OrderPartConsts.RETAIL_PART_6HOUR_REMIND, hour6Remind);
        }};

        // 三次任务提交
        taskMap.forEach((k, v) -> {
            Job job = new Job();
            job.setTaskId(TaskConsts.TASK_ID_RETAIN_PART + ":" + orderWork.getOrderId() + "_" + k.toString());
            job.setParam("orderId", orderWork.getOrderId().toString());
            job.setParam("workId", orderWork.getWorkId().toString());
            job.setParam(TaskManager.SHARD_FIELD, TaskConsts.TASK_ID_RETAIN_PART);
            job.setParam("execType", k.toString());
            job.setTriggerDate(v);
            logger.info("添加保留24小时配件task==>{}", job);
            taskManager.submitTask2(job);
        });
    }

    /**
     * 添加定时评价任务
     *
     * @param orderId
     */
    private void addCommentJob(Long orderId) {
        Job job = new Job();
        job.setTaskId(TaskConsts.TASK_ID_COMMENT + ":" + orderId);
        job.setParam("orderId", orderId.toString());
        job.setParam(TaskManager.SHARD_FIELD, TaskConsts.TASK_ID_COMMENT);
        Date date = DateUtil.addDays(DateUtil.getNow(), OrderConsts.COMMENT_DEFAULT_DAYS);
        taskManager.submitTask(job, -1, DateUtil.dateFormatToString(date, DateUtil.FORMAT_DEFAULT));
    }

    /**
     * 完成位置
     *
     * @param omsOperator
     * @return
     */
    private CompletePositionDTO getCompletePosition(OmsOperator omsOperator) {

        Double distance = null;
        if (omsOperator.getLongitude() != null && omsOperator.getLatitude() != null) {
            OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(omsOperator.getOrderId());
            if (orderDetail.getLongitude() != null && orderDetail.getLatitude() != null) {
                distance = MathUtil.GetDistance(orderDetail.getLongitude(), orderDetail.getLatitude(), omsOperator.getLongitude(), omsOperator.getLatitude());
            }
        }

        CompletePositionDTO completePositionDTO = new CompletePositionDTO();
        Integer completeOnSite;

        // 是否现场完成
        if (distance != null && distance <= 500) {// 500米以内算现场
            completeOnSite = GlobalConsts.YES;
        } else {
            completeOnSite = GlobalConsts.NO;
        }

        completePositionDTO.setCompleteOnSite(completeOnSite);

        // 完成日志
        StringBuilder sb = new StringBuilder();
        if (distance == null) {
            sb.append("完成距离：位置离线，");
        } else {
            sb.append("完成距离：" + String.format("%.2f KM，", distance / 1000));
        }

        return completePositionDTO;
    }

    /**
     * 记录工程师联系用户
     *
     * @param contactUserDTO
     */
    @Override
    public void saveContactUser(ContactUserDTO contactUserDTO) throws OmsBaseException {

        masterWorkBService.saveContactUser(contactUserDTO);
        // 普通通话记录
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(contactUserDTO.getOrderId());
        if (orderDetail.getBindStatus() == GlobalConsts.NONE) {
            // 处理通话记录
            CallRecordLogDTO callRecordLogDTO = masterWorkBService.processNormalCallRecord(contactUserDTO);
            logger.debug("保存通话记录 callRecordLogDTO:{}", JSONObject.toJSONString(callRecordLogDTO));
            // 保存通话记录
            callRecordLogDTO.setOrderId(contactUserDTO.getOrderId());
            callRecordLogDTO.setWorkId(contactUserDTO.getWorkId());
            callRecordBService.processNormalRecordLog(callRecordLogDTO);
        }

        // 发送消息
        orderWorkProgrammeBService.sendOperateInfo(contactUserDTO.getOrderId(), AppConsts.OPERATE_TYPE_CONTACT);

    }

    /**
     * 记录工程师联系用户
     *
     * @param contactUserDTO
     */
    @Override
    public void saveContactUserTime(ContactUserDTO contactUserDTO) throws OmsBaseException {

        masterWorkBService.saveContactUser(contactUserDTO);

    }

    /**
     * 查询会员单审核
     */
    @Override
    public MemberReviewDTO getMemberReview(Integer plat, Long orderId, Long workId, Integer masterId) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findMasterWorkDetail(orderId, workId, masterId);
        if (orderWork == null) {
            throw new OmsBaseException("无效的工单");
        }

        if (!Objects.equals(orderWork.getResultStatus(), OrderGlobalConsts.WORK_RESULT_DOING)) {
            throw new OmsBaseException("工单不在进行中");
        }

        OrderMember orderMember = orderMemberService.findMemberByKey(orderId);
        if (orderMember == null) {
            throw new OmsBaseException("不是会员单");
        }

        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderId);

        MemberReviewDTO memberReviewDTO = new MemberReviewDTO();

        // 全家享会员客服电话
        memberReviewDTO.setMemberServiceNumber(baseCodeService.getMemberServicePhone(plat));

        // 全家享会员单可以操作的距离,单位米
        memberReviewDTO.setMemberOrderOperationDistance(baseCodeService.getMemberOrderOperationDistance(plat));

        // 经纬度
        memberReviewDTO.setLongitude(orderDetail.getLongitude());
        memberReviewDTO.setLatitude(orderDetail.getLatitude());

        return memberReviewDTO;
    }

    /**
     * 查询会员单审核信息(重写)
     */
    @Override
    public MemberReviewDTO getMemberVerifyInfo(Integer plat, Long orderId, Long workId, Integer masterId) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findMasterWorkDetail(orderId, workId, masterId);
        if (orderWork == null) {
            throw new OmsBaseException("无效的工单");
        }

        if (!Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING)) {
            throw new OmsBaseException("工单不在进行中");
        }

        OrderMember orderMember = orderMemberService.findMemberByKey(orderId);
        if (orderMember == null) {
            throw new OmsBaseException("不是会员单");
        }

        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderId);

        MemberReviewDTO memberReviewDTO = new MemberReviewDTO();

        // 全家享会员客服电话
        memberReviewDTO.setMemberServiceNumber(baseCodeService.getMemberServicePhone(plat));

        // 全家享会员单可以操作的距离,单位米
        memberReviewDTO.setMemberOrderOperationDistance(baseCodeService.getMemberOrderOperationDistance(plat));

        // 经纬度
        memberReviewDTO.setLongitude(orderDetail.getLongitude());
        memberReviewDTO.setLatitude(orderDetail.getLatitude());

        return memberReviewDTO;
    }

    /**
     * (师傅)审核会员单(重写)
     */
    @Override
    public void masterVerifyMemberOrder(MasterVerifyMemberOrderDTO masterVerifyMemberOrderDTO) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findMasterWorkDetail(masterVerifyMemberOrderDTO.getOrderId(), masterVerifyMemberOrderDTO.getWorkId(), masterVerifyMemberOrderDTO.getMasterId());
        if (orderWork == null) {
            throw new OmsBaseException("无效的工单");
        }

        if (!Objects.equals(orderWork.getResultStatus(), OrderGlobalConsts.WORK_RESULT_DOING)) {
            throw new OmsBaseException("工单不在进行中");
        }

        // 保存审核信息
        OrderMemberMasterReviewDTO dto = BeanMapper.map(masterVerifyMemberOrderDTO, OrderMemberMasterReviewDTO.class);
        boolean reviewSuccess = orderMemberBService.saveMasterReview(dto);
    }

    @Override
    public MasterWorkWarrantyDTO getWorkWarranty(Long orderId, Long workId) {
        MasterWorkWarrantyDTO warrantyDTO = new MasterWorkWarrantyDTO();

        // 订单未完成
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);

        if (Objects.equals(OrderConsts.ORDER_TYPE_REFUND, orderWork.getType())) {
            warrantyDTO.setShow(GlobalConsts.NO);
            warrantyDTO.setMsg("退款订单无保修卡");
            return warrantyDTO;
        }

        if (Objects.equals(OrderConsts.ORDER_TYPE_REWORK, orderWork.getType())) {
            warrantyDTO.setShow(GlobalConsts.NO);
            warrantyDTO.setMsg("返修订单无保修卡");
            return warrantyDTO;
        }

        if (orderWork.getStatus() < OrderStatusConsts.WORK_STATUS_COMPLETE) {
            warrantyDTO.setShow(GlobalConsts.NO);
            warrantyDTO.setMsg("订单未完成");
            return warrantyDTO;
        }

        Map<Long, Integer> warrantyMap = zsOrderWarrantyBService.isExistWarrantyInfoMap(orderWork.getOrderId(), orderWork.getWorkId());
        boolean notExistWarranty = !warrantyMap.containsValue(GlobalConsts.YES);
        if (notExistWarranty) {
            warrantyDTO.setShow(GlobalConsts.NO);
            warrantyDTO.setMsg("当前产品的服务项目无保修卡");
            return warrantyDTO;
        }

        // 注意：若是延保订单，并且用延保优惠券全额优惠，则不发放保修卡
        boolean isOrderMemberAndFullDiscount = orderMemberBService.verifyOrderMemberAndDiscount(orderWork.getOrderId(), orderWork.getWorkId());
        if (isOrderMemberAndFullDiscount) {
            warrantyDTO.setShow(GlobalConsts.NO);
            warrantyDTO.setMsg("当前工单无保修卡");
            return warrantyDTO;
        }

        // 保修卡
        OrderWarranty orderWarranty = orderWarrantyService.findByOrderId(orderId);
        if (orderWarranty != null && !NumberUtil.isNullOrZero(orderWarranty.getUserId())) {

            // 支付宝渠道不弹出 保修卡二维码
            boolean isAliChannel = Objects.equals(GlobalConsts.CHANNEL_ALIPAY_SERV_ID, orderWork.getChannelId()) || Objects.equals(GlobalConsts.CHANNEL_ALIPAY_APP_ID, orderWork.getChannelId());
            if (isAliChannel) {
                warrantyDTO.setShow(GlobalConsts.NO);
                warrantyDTO.setMsg("请在支付宝小程序或生活号查看保修卡");
                return warrantyDTO;
            }

            // 上门扫码用户
            boolean visitUser = Objects.equals(orderWarranty.getUserId(), orderWork.getVisitUserId());
            if (visitUser) {
                warrantyDTO.setShow(GlobalConsts.NO);
                warrantyDTO.setMsg("请在上门扫码用户的微信公众号查看保修卡");
                return warrantyDTO;
            }

            // 支付扫码用户
            boolean payUser = Objects.equals(orderWarranty.getUserId(), orderWork.getCustomerId());
            if (payUser) {
                warrantyDTO.setShow(GlobalConsts.NO);
                warrantyDTO.setMsg("请在支付扫码用户的微信公众号查看保修卡");
                return warrantyDTO;
            }

            // 下单用户
            boolean addOrderUser = Objects.equals(orderWarranty.getUserId(), orderWork.getUserId());
            if (addOrderUser) {
                warrantyDTO.setShow(GlobalConsts.NO);
                warrantyDTO.setMsg("请在下单用户绑定的微信公众号查看保修卡");
                return warrantyDTO;
            }
        }

        // 获取二维码
        String qrCode = zsOrderPayBService.getWechatQrcode(orderId, WechatQrConststs.QR_TYPE_MASTER_WARRANTY);
//        String qrCode = zsOrderPayBService.getWechatQrcode(orderId, "TempWarray", "");
        if (StringUtil.isBlank(qrCode)) {
            warrantyDTO.setShow(GlobalConsts.NO);
            warrantyDTO.setMsg("获取保修卡二维码失败");
            return warrantyDTO;
        }

        warrantyDTO.setShow(GlobalConsts.YES);
        warrantyDTO.setQrCode(qrCode);
        return warrantyDTO;
    }

    @Override
    public MasterWorkVisitQrCodeDTO getWorkVisitQrCode(Long orderId, Long workId) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        if (Objects.equals(GlobalConsts.PLAT_MARK_SAAS, orderWork.getPlatWork())) {
            return MasterWorkVisitQrCodeDTO.builder().show(GlobalConsts.NO).build();
        }
        MasterWorkVisitQrCodeDTO visitQrCodeDTO = new MasterWorkVisitQrCodeDTO();

        // 已领单、已上门状态可以操作
        if (!Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_TAKE) && !Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_VISIT)) {
            throw new OmsBaseException("工单非领单或者已上门状态");
        }

        // 查询是否有扫码用户
        OrderChangeRecord changeRecord = orderChangeRecordService.getChangeRecordByOrderId(orderId);
        if (Objects.nonNull(changeRecord) && Objects.nonNull(changeRecord.getFirstVisitScanTime())) {
            // 检验用户是否关注公众号
            Boolean isAttentionWechat = this.checkAttentionWeChat(orderWork);
            if (isAttentionWechat) {
                visitQrCodeDTO.setShow(GlobalConsts.NO);
                visitQrCodeDTO.setMsg("此订单已有关注用户，无需再次关注");
                return visitQrCodeDTO;
            }
        }

        // 判断上门时间  Xiewenbing 2020.03.11
        Date curTime = new Date();
        Date dutyTimeStart = new Date(orderWork.getDutyTime().getTime() - 120 * 60 * 1000);

        // 1、F-保内订单，上门时不限制时间 2、C-保外订单，需2小时内才可上门
        if (Objects.equals(orderWork.getBizType(), com.zmn.consts.GlobalConsts.BIZ_TYPE_C)) {
            if (curTime.getTime() < dutyTimeStart.getTime()) {
                String showMsg;

                // 预约时间是当天
                if (DateUtil.getDateStart(curTime).getTime() == DateUtil.getDateStart(orderWork.getDutyTime()).getTime()) {
                    showMsg = String.format("请在%s ~ %s上门 ", DateUtil.toString(dutyTimeStart, "HH时mm分"), DateUtil.toString(orderWork.getDutyTime(), "HH时mm分"));
                } else {
                    showMsg = String.format("请在%s，%s左右上门", DateUtil.getDateStr(orderWork.getDutyTime(), curTime), DateUtil.toString(orderWork.getDutyTime(), "HH时mm分"));
                }
                throw new OmsBaseException(showMsg);
            }
        }

        // 获取二维码
        String qrCode = zsOrderPayBService.getWechatQrcode(orderId, WechatQrConststs.QR_TYPE_MASTER_VISIT);
        if (StringUtil.isBlank(qrCode)) {
            throw new OmsBaseException("获取上门二维码失败");
        }

        visitQrCodeDTO.setShow(GlobalConsts.YES);
        visitQrCodeDTO.setQrCode(qrCode);
        return visitQrCodeDTO;
    }

    /**
     * 检验是否可以修改预约时间
     *
     * @param modifyDutyTimeDTO
     */
    @Override
    public com.zmn.oms.common.dto.ResultDTO<Integer> checkDutyTimeCount(ModifyDutyTimeDTO modifyDutyTimeDTO) throws OmsBaseException {
        OrderDuty orderDuty = null;
        Long orderId = modifyDutyTimeDTO.getOrderId();

        OrderDutyQuery orderDutyQuery = new OrderDutyQuery();
        orderDutyQuery.setPlat(modifyDutyTimeDTO.getPlat());
        orderDutyQuery.setType(OrderGateTypeConsts.GATE_APP);
        orderDutyQuery.setAppointmentOrChange(ConfOrderDutyConsts.APPOINTMENT_OR_CHANGE_CHANGE);
        logger.info("orderDutyService#listByQuery 入参:[{}]", orderDutyQuery);
        List<OrderDuty> orderDutyList = orderDutyService.listByQuery(orderDutyQuery);
        logger.info("orderDutyService#listByQuery 出参:[{}]", orderDutyList);
        if (CollectionUtils.isNotEmpty(orderDutyList)) {
            orderDuty = orderDutyList.get(0);
        }
        if (orderDuty == null || NumberUtil.isNullOrZero(orderDuty.getNumberOfContractChanges())) {
            return com.zmn.oms.common.dto.ResultDTO.success(GlobalConsts.YES);
        }

        if (NumberUtil.isNullOrZero(orderId)) {
            return com.zmn.oms.common.dto.ResultDTO.success(GlobalConsts.YES);
        }

        OrderChangeRecord orderChangeRecord = orderChangeRecordService.getChangeRecordByOrderId(orderId);
        if (orderChangeRecord == null) {
            return com.zmn.oms.common.dto.ResultDTO.success(GlobalConsts.YES);
        }

        if (orderChangeRecord.getAppDutyTimeModifyCount() >= orderDuty.getNumberOfContractChanges()) {
            return com.zmn.oms.common.dto.ResultDTO.success(new Integer(GlobalConsts.NO), "订单改时间总次数已超限，请联系后台人员改动");
        }

        return com.zmn.oms.common.dto.ResultDTO.success(GlobalConsts.YES);
    }

    @Override
    public void updateDutyTimeWithNoStock(ModifyDutyTimeDTO modifyDutyTimeDTO) throws OmsBaseException {
// 验证预约时间范围
        zsOrderWorkScheduleBService.validateDutyTime(modifyDutyTimeDTO.getOrderId(), modifyDutyTimeDTO.getPlat(), ConfOrderDutyConsts.TYPE_ENGINEER_APP, modifyDutyTimeDTO.getDutyTime());

        if (Objects.nonNull(modifyDutyTimeDTO.getDutyTime())) {
            modifyDutyTimeDTO.setDutyStatus(OrderDutyConsts.DUTY_STATUS_SUCCESS);
            modifyDutyTimeDTO.setNextContactTime(null);
        }

        // 预约时间修改 直接修改工单
//        Boolean needBack = false;
        OrderWork orderWork = orderWorkService.findMasterWorkDetail(modifyDutyTimeDTO.getOrderId(), modifyDutyTimeDTO.getWorkId(), modifyDutyTimeDTO.getMasterId());

        // 判断工单状态是否是已领单和已上门，是否进行中
        if (!(Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_TAKE) || Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_VISIT)) || !Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING)) {
            throw new OmsBaseException("工单当前状态不允许修改预约时间");
        }

        // 更新预约时间
        masterWorkBService.updateDutyTimeWithNoStock(modifyDutyTimeDTO);
    }

    /**
     * 修改预约时间
     *
     * @param modifyDutyTimeDTO
     */
    @Override
    public void updateDutyTime(ModifyDutyTimeDTO modifyDutyTimeDTO) throws OmsBaseException {

        // 工单查询及判断
        OrderWork orderWork = orderWorkService.findMasterWorkDetail(modifyDutyTimeDTO.getOrderId(), modifyDutyTimeDTO.getWorkId(), modifyDutyTimeDTO.getMasterId());
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException("无效的工单");
        }

        // 判断工单状态是否是已领单和已上门，是否进行中
        if (!(Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_TAKE) || Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_VISIT)) || !Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING)) {
            throw new OmsBaseException("工单当前状态不允许修改预约时间");
        }

        // 验证预约时间范围
        zsOrderWorkScheduleBService.validateModifyDutyTime(orderWork, ConfOrderDutyConsts.TYPE_ENGINEER_APP, modifyDutyTimeDTO.getDutyTime());

        if (Objects.nonNull(modifyDutyTimeDTO.getDutyTime())) {
            modifyDutyTimeDTO.setDutyStatus(OrderDutyConsts.DUTY_STATUS_SUCCESS);
            modifyDutyTimeDTO.setNextContactTime(null);
        }

        // 更新预约时间
        masterWorkBService.updateDutyTime(modifyDutyTimeDTO);
    }

    /**
     * 改派工程师
     *
     * @param changeMasterDTO
     */
    @Override
    public void updateMaster(ChangeMasterDTO changeMasterDTO) throws OmsBaseException {
        // 查询工程师信息
        // todo fubiao
        logger.info("updateMaster#getEngineerDetailById 入参 [{}]", changeMasterDTO.getNewMasterId());
        ResponseDTO<ForeignEngineerDetailInfoDRO> cacheEngineerByEngineerId = engineerListRemoteService.getEngineerDetailById(changeMasterDTO.getNewMasterId());
        logger.info("updateMaster#getEngineerDetailById 出参 [{}]", JSON.toJSONString(cacheEngineerByEngineerId));
        ForeignEngineerDetailInfoDRO baseEngineerDRO = cacheEngineerByEngineerId.getData();
        if (!cacheEngineerByEngineerId.isSuccess() || baseEngineerDRO == null) {
            throw new OmsBaseException("工程师不存在");
        }

        OrderDistributeDTO distributeDTO = BeanMapper.map(changeMasterDTO, OrderDistributeDTO.class);

        distributeDTO.setMasterId(changeMasterDTO.getNewMasterId());
        distributeDTO.setMasterName(baseEngineerDRO.getRealName());
        distributeDTO.setMasterPhone(baseEngineerDRO.getMobile());

        // 设置成已派单
        distributeDTO.setStatus(OrderStatusConsts.WORK_STATUS_DISTRIBUTE);
        // 派单路径
        distributeDTO.setDistributeWay(OrderDistributeConsts.DISTRIBUTE_WAY_SP);
        // 派单规则
        distributeDTO.setDistributeRule(OrderDistributeConsts.DISTRIBUTE_RULE_SIMPLE);
        // 派单入口
        distributeDTO.setDistributeEntry(OrderDistributeConsts.DISTRIBUTE_ENTRY_APP);

        zsCustomWorkBService.saveDistribute(distributeDTO);
    }

    /**
     * 获取工单可派单工程师列表
     *
     * @param orderId
     * @param workId
     */
    @Override
    public WorkDistributeMasterDTO getWorkDistributeMasterList(Long orderId, Long workId) throws OmsBaseException {
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderId);
        WorkDistributeMasterDTO workDistributeMasterDTO = new WorkDistributeMasterDTO();

        // 1.只有新单能APP转派
        if (!Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_NEW)) {
            return workDistributeMasterDTO;
        }

        // 创建派单视图对象
        DistributeVO distributeVO = zsDistributeWorkBService.buildDistributeVO(orderWork, orderDetail, null);

        // 2.特殊派单，不能APP转派
        if (distributeVO.getDistributeBizType() == OrderDistributeConsts.DISTRIBUTE_BIZ_TYPE_SPECIAL) {
            return workDistributeMasterDTO;
        }

        distributeVO.setDistributeEntry(OrderDistributeConsts.DISTRIBUTE_ENTRY_APP);
        distributeVO.setOnlyBaseMasterList(true);
        distributeVO.setSimpleStatus(true);
        distributeVO.setRecommendStatus(false);
        distributeVO.setFairStatus(false);

        // 查询派单工程师
        zsDistributeWorkBService.getOrderDistributeMasterList(orderWork, orderDetail, distributeVO, null);

        if (distributeVO.getMasterList() != null && distributeVO.getMasterList().size() > 0) {
            List<WorkDistributeMasterItemDTO> masterList = BeanMapper.mapList(distributeVO.getMasterList(), WorkDistributeMasterItemDTO.class);
            workDistributeMasterDTO.setMasterList(masterList);
        }

        return workDistributeMasterDTO;
    }


    /**
     * 验证完成核销码
     *
     * @param orderId      订单id
     * @param workId       工单id
     * @param completeCode 完成核销码
     * @throws OmsBaseException
     */
    @Override
    public void verifyCompleteCode(Long orderId, Long workId, String completeCode) throws OmsBaseException {

        // 完成码判断
        if (StringUtil.isBlank(completeCode)) {
            throw new OmsBaseException("完成码不能为空");
        }

        // 查找工单
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException("无效的工单");
        }

        // 非厂商单不用验证
        if (!Objects.equals(orderWork.getSourceType(), OrderConsts.ORDER_SOURCE_TYPE_FACTORY)) {
            return;
        }

        /*
        // 拼多多渠道从渠道方进行验证
        if (PinDuoDuoUtil.isPinDuoDuoChannel(orderWork.getChannelId())){
            pinDuoDuoService.sendVerifyCheckToPinDuoDuo(orderId, workId, completeCode, orderWork.getChannelId());
            return;
        }
        */

        // 一般厂商单
        String featureCode = EncodeUtil.getFeatureCode(orderWork.getWorkId(), 4);
        if (featureCode.compareToIgnoreCase(completeCode) != 0) {
            throw new OmsBaseException("输入的完成码不正确，请重新输入");
        }

        // 云丁渠道需要提交完成资料
        if (orderWork.getChannelId() == OrderConsts.CHANNEL_ID_YUNDING_LOCK) {
            yundingService.verifyCompleteOrder(orderId, workId);
        }

        // 云丁渠道需要提交完成资料
        if (orderWork.getChannelId() == OrderConsts.CHANNEL_ID_SF_INSTALL) {
            shunfengService.verifyCompleteOrder(orderId, workId);
        }

        // 保存到redis
        String redisKey = String.format(RedisKeyConsts.ORDER_SERVICE_COMPLETE_KEY, String.valueOf(orderWork.getWorkId()));
        redisManager.set(redisKey, String.valueOf(true));
    }

    @Override
    public MasterQuotationDiscountDTO getQuotationAndDiscountInfo(OrderWork orderWork) throws OmsBaseException {
        Integer masterId = orderWork.getMasterId();

        // 是否有服务项目 - 存在价格
        boolean haveServiceItem = false;
        List<OrderServiceItem> orderServiceItemList = orderServiceItemService.listByOrderId(orderWork.getOrderId());
        if (CollectionUtils.isNotEmpty(orderServiceItemList)) {
            haveServiceItem = true;
        }

        // 获取报价人信息
        boolean isUserOperation = false;
        OrderOperation orderOperation = orderOperationService.findBykey(orderWork.getOrderId());
        if (Objects.nonNull(orderOperation)) {
            isUserOperation = Lists.newArrayList(GlobalConsts.OPERATE_USER_TYPE_MASTER, GlobalConsts.OPERATE_USER_TYPE_USER).contains(orderOperation.getQuotationType());
        }
        // 是否确认过报价
        boolean haveConfirmQuotation = masterWorkBService.haveConfirmQuotation(orderWork.getOrderId());

        ResponseDTO<Integer> quotationResp;
        try {
            quotationResp = quotationListRemoteService.checkHaveQuotation(orderWork.getOrderId());
            logger.info("#oms#checkHaveQuotation#检查订单是否有报价入参orderId={},出参数={}", orderWork.getOrderId(), quotationResp);
            if (!quotationResp.isSuccess()) {
                throw new OmsBaseException("获取报价信息失败");
            }
        } catch (Exception ex) {
            logger.error(String.format("订单号%s，检查订单是否有报价接口checkHaveQuotation异常了:%s", orderWork.getOrderId(), ex.getMessage()), ex);
            throw new OmsBaseException("获取报价信息失败");
        }

        // 获取师傅优惠次数
        // todo fubiao
        logger.info("getQuotationAndDiscountInfo#getDiscountByEngineerId 入参 [{}]", masterId);
        ResponseDTO<EngineerDiscountDRO> applyCountResp = engineerDiscountListRemoteService.getDiscountByEngineerId(masterId);
        logger.info("getQuotationAndDiscountInfo#getDiscountByEngineerId 出参 [{}]", JSON.toJSONString(applyCountResp));
        logger.info("#oms#getSaleApplyCountByEngineer#orderId={},获取师傅优惠次数入参masterId={},出参数={}", orderWork.getOrderId(), masterId, applyCountResp);
        if (!applyCountResp.isSuccess()) {
            throw new OmsBaseException("获取优惠次数失败");
        }
        EngineerDiscountDRO saleApplyCountDRO = applyCountResp.getData();

        // 报价ID
        Integer quotationId = quotationResp.getData();
        // 检查订单是否有小程序报价
        // boolean haveQuotation = NumberUtil.isNotNullOrZero(quotationId);
        // 检查订单工程师是否申请过优惠
        String redisKey = String.format(RedisKeyConsts.MASTER_APPLY_DISCOUNT_KEY, String.valueOf(orderWork.getOrderId()), masterId);
        boolean haveApplyDiscount = redisManager.exists(redisKey);
        // 计价器工单
        boolean isFaultOrder = servItemBService.isQuotationType(orderWork.getServItemType());

        // 一：用户已确认报价 -- 计价器工单并且存存在服务项目
        Integer confirmQuotationFlag = (isFaultOrder && haveServiceItem) ? GlobalConsts.YES : GlobalConsts.NO;

        //  二.1.判断历史订单是否可以操作优惠--  已经申请过优惠 && 存在服务项目
        boolean orderCanApplyDiscount = haveApplyDiscount && haveServiceItem;
        //     2.申请优惠 -- 能申请优惠：有服务项目 && 未超限
        Integer applyDiscountFlag = haveServiceItem && !Objects.equals(saleApplyCountDRO.getUsedCount(), saleApplyCountDRO.getUpperLimitCount()) ? GlobalConsts.YES : GlobalConsts.NO;

        // 如果用户议价了，且非用户修改了报价则清空报价id(app跳转至原生页面)
        if (NumberUtil.isNotNullOrZero(quotationId) && !isUserOperation) {
            quotationId = null;
        }

        MasterQuotationDiscountDTO masterQuotationDTO = BeanMapper.map(saleApplyCountDRO, MasterQuotationDiscountDTO.class);
        masterQuotationDTO.setConfirmQuotationFlag(confirmQuotationFlag);
        masterQuotationDTO.setQuotationId(quotationId);
        masterQuotationDTO.setApplyDiscountFlag(applyDiscountFlag);
        masterQuotationDTO.setHaveConfirmQuotation(haveConfirmQuotation ? GlobalConsts.YES : GlobalConsts.NO);
        if (orderCanApplyDiscount) {
            masterQuotationDTO.setApplyDiscountFlag(GlobalConsts.YES);
        }

        String redisKeyReview = String.format(RedisKeyConsts.MASTER_APPLY_DISCOUNT_REVIEWING_KEY, String.valueOf(orderWork.getOrderId()), orderWork.getMasterId());
        if (redisManager.exists(redisKeyReview)) {
            masterQuotationDTO.setIsReviewing(GlobalConsts.YES);
        } else {
            masterQuotationDTO.setIsReviewing(GlobalConsts.NO);
        }

        // 难度系数：维修订单
        if (!haveConfirmQuotation && OrderConsts.DIFFICULT_RETIO_SERVICE_CATEGID.contains(orderWork.getServCategId()) && DIFFICULT_RATIO_CITY.contains(orderWork.getCityId())) {
            // 已选中的计价器难度系数
            OrderExtend orderExtend = orderExtendService.findOrderExtendByOrderId(orderWork.getOrderId());
            if (Objects.isNull(orderExtend) || Objects.isNull(orderExtend.getDifficultRatioId())) {
                masterQuotationDTO.setHasDifficultRetio(GlobalConsts.YES);
            }
        }
        masterQuotationDTO.setHasDifficultRetio(Optional.ofNullable(masterQuotationDTO.getHasDifficultRetio()).orElse(GlobalConsts.NO));
        if (!Objects.equals(orderWork.getServItemType(), OrderConsts.SERVICE_ITEM_TYPE_FAULT)) {
            masterQuotationDTO.setHasDifficultRetio(GlobalConsts.NO);
        }
        return masterQuotationDTO;
    }

    @Override
    public WorkQuotationShowDTO getQuotationShow(OrderWork orderWork) {
        return masterWorkBService.getQuotationShow(orderWork);
    }

    @Override
    public MasterWorkOperateCheckInfoDTO getMasterWorkOperateCheckInfo(Long orderId, Long workId) {
        Objects.requireNonNull(orderId, "订单号不能为空");
        Objects.requireNonNull(workId, "工单号不能为空");

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        Objects.requireNonNull(orderWork, "工单信息不存在");


        MasterWorkOperateCheckInfoDTO operateCheckInfoDTO = new MasterWorkOperateCheckInfoDTO();

        // 判断是否为墙面订单
        WallTypeEnum wallTypeEnum = wallQuotationBService.isWallOrder(PilotCheckQuery.builder()
                .categId(orderWork.getShowCategId())
                .channelId(orderWork.getChannelId())
                .cityId(orderWork.getCityId())
                .servCategId(orderWork.getServCategId())
                .pilotTypeId(PilotTypeEnum.WALL_QUOTE.getId())
                .build(), orderWork.getServProductGroupId(), orderWork.getServItemType());

        if (Objects.nonNull(wallTypeEnum)) {
            // 墙面订单处理
            WallQuotation wallQuotation = wallQuotationService.findById(workId);
            if (Objects.nonNull(wallQuotation) && Objects.equals(wallQuotation.getWallStatus(), GlobalConsts.YES)) {
                operateCheckInfoDTO.setHasConfirmQuotation(GlobalConsts.YES);
            } else {
                operateCheckInfoDTO.setHasConfirmQuotation(GlobalConsts.NO);
            }
            if (Objects.equals(wallTypeEnum.getCode(), WallTypeEnum.WALL_QUOTATION.getCode())) {
                operateCheckInfoDTO.setIsWallQuotation(GlobalConsts.YES);
                operateCheckInfoDTO.setIsWallWaterproofQuotation(GlobalConsts.NO);
            } else {
                operateCheckInfoDTO.setIsWallQuotation(GlobalConsts.NO);
                operateCheckInfoDTO.setIsWallWaterproofQuotation(GlobalConsts.YES);
            }
        } else {
            // 是否确认过报价
            boolean hasConfirmQuotation = masterWorkBService.haveConfirmQuotation(orderWork.getOrderId());
            operateCheckInfoDTO.setHasConfirmQuotation(hasConfirmQuotation ? GlobalConsts.YES : GlobalConsts.NO);
            operateCheckInfoDTO.setIsWallQuotation(GlobalConsts.NO);
            operateCheckInfoDTO.setIsWallWaterproofQuotation(GlobalConsts.NO);
        }

        operateCheckInfoDTO.setBizType(orderWork.getBizType());
        operateCheckInfoDTO.setServItemType(orderWork.getServItemType());
        operateCheckInfoDTO.setStatus(orderWork.getStatus());
        operateCheckInfoDTO.setResultStatus(orderWork.getResultStatus());
        operateCheckInfoDTO.setShowProductId(orderWork.getShowProductId());
        operateCheckInfoDTO.setChannelId(orderWork.getChannelId());

        OrderExtend orderExtend = orderExtendService.findOrderExtendByOrderId(orderId);
        // 形象照
        if (AppConsts.MASTER_PICTURE_CHECK_PLAT.contains(orderWork.getPlatWork())) {
            if (orderExtend == null || StringUtils.isBlank(orderExtend.getMasterSrc())) {
                operateCheckInfoDTO.setNeedUploadMasterPicture(GlobalConsts.YES);
            }
        }

        // 是否操作过上门扫码
        if (Objects.nonNull(orderExtend)) {
            operateCheckInfoDTO.setHasOperateVisitScan(orderExtend.getOperateVisitScan());
        }

        // 是否有产品
        operateCheckInfoDTO.setHasProduct(NumberUtil.isNotNullOrZero(orderWork.getProductId()) ? GlobalConsts.YES : GlobalConsts.NO);

        // 工程师是否已确认检测报告
        OrderQuotationProcess process = orderQuotationProcessService.findByOrderId(orderId);
        if (Objects.nonNull(process)) {
            operateCheckInfoDTO.setIsConfirmFault(Objects.equals(process.getConfirmStatus(), GlobalConsts.YES) ? GlobalConsts.YES : GlobalConsts.NO);
            operateCheckInfoDTO.setIsStartCheck(Objects.isNull(process.getStartCheckTime()) ? GlobalConsts.NO : GlobalConsts.YES);
            operateCheckInfoDTO.setIsSubmitCheckReport(Objects.equals(process.getReportSubmitStatus(), GlobalConsts.YES) ? GlobalConsts.YES : GlobalConsts.NO);
            operateCheckInfoDTO.setHasCheckProductByEngineer(process.getCheckProductStatus());
            operateCheckInfoDTO.setHasAgreeResult(NumberUtil.isNullOrZero(process.getAgreeStatus()) ? GlobalConsts.NO : GlobalConsts.YES);
        }

        // 一口价订单是否有产品和品牌
        if (Objects.equals(orderWork.getFinalPrice(), GlobalConsts.YES)) {
            operateCheckInfoDTO.setFinalPrice(GlobalConsts.YES);
            if (Objects.nonNull(orderWork.getProductId()) && Objects.nonNull(orderWork.getProductBrandId())) {
                operateCheckInfoDTO.setHasCheckProductByEngineer(GlobalConsts.YES);
            }
        }

        // 是否走默认服务流程
        if (Objects.equals(orderWork.getServItemType(),OrderConsts.SERVICE_ITEM_TYPE_ORDER)){
            ResponseDTO<TagsDRO> responseDTO = tagsListRemoteService.getById(serviceOrderProcessTagId);
            if (responseDTO.isSuccess()){
                TagsDRO tagsDRO = responseDTO.getData();
                if (Objects.nonNull(tagsDRO) && Objects.equals(tagsDRO.getStatus(),GlobalConsts.YES) &&
                        NumberUtil.isNotNullOrZero(orderWork.getProductId())){
                    operateCheckInfoDTO.setServiceOrderProcess(GlobalConsts.YES);
                }
            }
        }


        OrderAttachmentQuery query = new OrderAttachmentQuery();
        query.setOrderId(orderWork.getOrderId());
        query.setWorkId(orderWork.getWorkId());
        query.setChannelId(orderWork.getChannelId());
        query.setBizType(orderWork.getBizType());
        query.setType(OrderAttachmentTypeEnum.CONSTS_ZBZ);
        query.setServCategId(orderWork.getServCategId());
        query.setCityId(orderWork.getCityId());
        query.setProductId(orderWork.getShowProductId());
        query.setBizLine(orderWork.getBizLine());


        List<OrderAttachment> orderAttachments = orderAttachmentService.listAttachmentByOrderId(orderId);
        // 获取装备照的配置
        ConfOrderAttachment equipmentPhotoConfig = confOrderAttachmentBService.getAttachmentConfigByQuery(query);
        if (Objects.nonNull(equipmentPhotoConfig) && Objects.equals(GlobalConsts.TWO, equipmentPhotoConfig.getMustUpload())) {
            operateCheckInfoDTO.setNeedUploadEquipmentPictureConf(GlobalConsts.YES);
            val hasEquipment = orderAttachments.stream().anyMatch(attachment -> Objects.equals(attachment.getType(), OrderAttachmentTypeEnum.ZBZ.getCode()));
            if (!hasEquipment) {
                operateCheckInfoDTO.setNeedUploadEquipmentPicture(GlobalConsts.YES);
            }
        }
        // 获取装备照的配置
        query.setType(OrderAttachmentTypeEnum.CONSTS_QJZP);
        ConfOrderAttachment purity = confOrderAttachmentBService.getAttachmentConfigByQuery(query);
        if (Objects.nonNull(purity) && Objects.equals(GlobalConsts.TWO, purity.getMustUpload())) {
            operateCheckInfoDTO.setNeedUploadPurityPictureConf(GlobalConsts.YES);
            val hasEquipment = orderAttachments.stream().anyMatch(attachment -> Objects.equals(attachment.getType(), OrderAttachmentTypeEnum.XJZP.getCode()));
            if (!hasEquipment) {
                operateCheckInfoDTO.setNeedUploadPurityPicture(GlobalConsts.YES);
            }
        }

        // 已上门前，不处理直接返回
        if (orderWork.getStatus() < OrderStatusConsts.WORK_STATUS_VISIT) {
            return operateCheckInfoDTO;
        }

        // 用户是否已扫码
        operateCheckInfoDTO.setIsUserScan(NumberUtil.isNullOrZero(orderWork.getVisitUserId()) ? GlobalConsts.NO : GlobalConsts.YES);


        // 计价器订单，难度系数：维修订单
        if (servItemBService.isQuotationNotThreeType(orderWork.getServItemType()) && OrderConsts.DIFFICULT_RETIO_SERVICE_CATEGID.contains(orderWork.getServCategId()) && DIFFICULT_RATIO_CITY.contains(orderWork.getCityId())) {
            // 已选中的计价器难度系数
            if (Objects.isNull(orderExtend) || Objects.isNull(orderExtend.getDifficultRatioId())) {
                operateCheckInfoDTO.setHasDifficultRetio(GlobalConsts.YES);
            }
        }

        // 是否展示代用户报价计价器二维码
        TagsQuery baseCodeMapDIO = new TagsQuery();
        baseCodeMapDIO.setPlat(orderWork.getPlatWork());
        baseCodeMapDIO.setOneTypeId(OrderConsts.BASE_CODE_MAP_ONE_TYPE_QUOTATION_EQCODE);
        baseCodeMapDIO.setTwoTypeId(OrderConsts.BASE_CODE_MAP_TWO_TYPE_QUOTATION_EQCODE);
        baseCodeMapDIO.setStatus(GlobalConsts.YES);
        ResponseDTO<List<TagsDRO>> listResponseDTO = tagsListRemoteService.listByTagsDIO(baseCodeMapDIO);
        if (listResponseDTO.isSuccess() && CollectionUtil.isNotNullOrEmpty(listResponseDTO.getData())) {
            operateCheckInfoDTO.setHasQuotationQRCode(GlobalConsts.YES);
        }

        return operateCheckInfoDTO;
    }

    private void syncOrderChannelInfoToERP(OmsOperator omsOperator, OrderWork orderWork, OrderDetail orderDetail) {
        if (!Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_NEW)) {
            return;
        }

        WorkChannelInfoDRO channelInfoDRO = BeanMapper.map(orderWork, WorkChannelInfoDRO.class);
        channelInfoDRO.setOrderReceiveAmount(orderWork.getTotalAmount());
        channelInfoDRO.setOrderCityId(orderWork.getCityId());
        channelInfoDRO.setOrderCityName(orderDetail.getCityName());
        channelInfoDRO.setOperatorId(Optional.ofNullable(omsOperator.getOperatorId()).orElse(Long.valueOf(com.zmn.consts.GlobalConsts.OPERATE_USER_TYPE_SYSTEM)).intValue());
        channelInfoDRO.setOperatorName(omsOperator.getOperator());
        channelInfoDRO.setChannelReceiveAmount(orderWork.getChannelPrepayAmount());

        // 完成时间
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderWork.getOrderId(), orderWork.getWorkId());
        channelInfoDRO.setCompleteTime(dbOrderWork.getCompleteTime());

        // 服务项内外结算价
        List<OrderServiceItem> orderServiceItems = orderServiceItemService.listByOrderId(orderWork.getOrderId());
        int internalSettlementPrice = 0;
        int externalSettlementPrice = 0;
        if (CollectionUtil.isNotNullOrEmpty(orderServiceItems)) {
            internalSettlementPrice = orderServiceItems.stream().filter(e -> NumberUtil.isNotNullOrZero(e.getInternalTotalPrice())).mapToInt(OrderServiceItem::getInternalTotalPrice).sum();
            externalSettlementPrice = orderServiceItems.stream().filter(e -> NumberUtil.isNotNullOrZero(e.getExternalTotalPrice())).mapToInt(OrderServiceItem::getExternalTotalPrice).sum();
        }
        if (NumberUtil.isNullOrZero(internalSettlementPrice)) {
            internalSettlementPrice = orderWork.getOriginalAmount();
        }
        if (NumberUtil.isNullOrZero(internalSettlementPrice)) {
            externalSettlementPrice = orderWork.getOriginalAmount();
        }
        channelInfoDRO.setInternalStatementAmount(internalSettlementPrice);
        channelInfoDRO.setOutStatementAmount(externalSettlementPrice);

        String key = String.format("%s_%s_%s", "orderwork_complete_sync_channelInfo", DateUtil.getNowTimestamp(), String.valueOf(orderWork.getWorkId()));
        String content = JSONObject.toJSONString(channelInfoDRO);

        logger.info("#completeOrder 完成同步渠道信息至ERP：key:{} content:{}", key, content);
        long time = System.currentTimeMillis() + 1 * 1000 * 60;// 延迟一分钟
        zmnMQSender.sendWithStartDeliverTime(MessageQueueTopicConstant.ZMN_TOPIC_ERP, MQ_TAG, key, content, time);
    }

    /**
     * 根据后台产品Id 更新节能减排能量值
     *
     * @param productId 后台产品Id
     * @param orderId   订单Id
     * @return
     */
    private void updateProductsEmissions(Long orderId, Integer productId) {
        if (NumberUtil.isNullOrZero(productId)) {
            return;
        }

        List<OrderProduct> products = orderProductService.listOrderProductByOrderId(orderId);
        if (CollectionUtil.isNullOrEmpty(products)) {
            return;
        }

        Integer productNum = Optional.ofNullable(products.get(0).getNumber()).orElse(GlobalConsts.NO);

        ResponseDTO<Integer> emissionsRemote = productForeignListRemoteService.getTotalEmissionsById(productId);
        logger.info("#oms#订单号={},获取节能减排入参productId={},出参resp={}", orderId, productId, emissionsRemote);
        Integer emissions = emissionsRemote.getData();
        if (!emissionsRemote.isSuccess() || emissionsRemote.getData() == null) {
            return;
        }
        // 更新节能减排数据
        OrderExtend orderExtend = new OrderExtend();
        orderExtend.setExtId(orderId);
        orderExtend.setProductsEmission(emissions * productNum);
        orderExtendService.updateOrderExtend(orderExtend);
    }

    /**
     * 检测迟到预警
     *
     * @param orderId
     * @return
     */
    private boolean checkLateWaring(Long orderId) {
        // 是否上门超时
        ResponseDTO<Boolean> visitTimeout = orderTimeoutWarningListService.checkOrderTimeoutStatus(orderId, OrderTimeoutTypeEnum.VISIT);
        logger.info("{}--是否上门超时orderTimeoutWarningListService#checkOrderTimeoutStatus，入参[{}，{}] 出参[{}]", "迟到赔", orderId, OrderTimeoutTypeEnum.VISIT, JSON.toJSONString(visitTimeout));
        if (visitTimeout.isSuccess() && visitTimeout.getData()) {
            return true;
        }
        return false;

    }

    /**
     * 获取app操作对应的返回信息
     *
     * @param orderId   订单Id
     * @param operateId 操作类型 {@See AppConsts}
     * @return
     */
    @Override
    public WorkResultDTO getOperateInfo(Long orderId, Integer operateId) {
        WorkResultDTO workResultDTO = new WorkResultDTO();

        workResultDTO.setOperateInfo(orderWorkProgrammeBService.getOperateInfo(orderId, operateId));

        return workResultDTO;
    }

    /**
     * 师傅审核订单取消
     *
     * @param cancelConfirmDTO
     * @throws OmsBaseException
     */
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_ENGINEER_REVIEW_CANCEL)
    @Override
    public void reviewOrderCancel(CancelConfirmDTO cancelConfirmDTO) throws OmsBaseException {
        TrackWorkQuery query = new TrackWorkQuery();
        query.setOrderId(cancelConfirmDTO.getOrderId());
        query.setWorkId(cancelConfirmDTO.getWorkId());
        query.setTrackContentIdList(TrackConfigConsts.TRACK_CONTENT_ID_CANCEL);
        query.setNotStatus(TrackConsts.TRACK_STATUS_FINISHED);
        ResponseDTO<List<TrackWorkDRO>> listResponseDTO = trackWorkListRemoteService.listTrackByQuery(query);
        if (!listResponseDTO.isSuccess() || CollectionUtil.isNullOrEmpty(listResponseDTO.getData())) {
            throw new OmsBaseException("用户取消申请跟单已被处理");
        }

        TrackWorkDRO trackWorkDRO = listResponseDTO.getData().stream().findFirst().get();
        if (Objects.equals(cancelConfirmDTO.getType(), GlobalConsts.YES)) {
            // 工程师选择用户同意继续服务，只修改工程师进行中表的待取消状态
            masterWorkingBService.updateMasterWorkingWaitCancelStatus(cancelConfirmDTO.getWorkId(), GlobalConsts.NO);
            // 添加跟单日志
            UpdateTrackRemarkDIO updateTrackRemarkDIO = new UpdateTrackRemarkDIO();
            updateTrackRemarkDIO.setOrderId(cancelConfirmDTO.getOrderId());
            updateTrackRemarkDIO.setWorkId(cancelConfirmDTO.getWorkId());
            updateTrackRemarkDIO.setTrackWorkId(trackWorkDRO.getTrackWorkId());
            updateTrackRemarkDIO.setRemark("工程师选择继续服务");
            updateTrackRemarkDIO.setOperator(cancelConfirmDTO.getOperator());
            updateTrackRemarkDIO.setOperatorType(cancelConfirmDTO.getOperatorType());
            updateTrackRemarkDIO.setOperatorId(cancelConfirmDTO.getOperatorId());
            trackWorkModifyRemoteService.addRemark(updateTrackRemarkDIO);
            // 完结跟单
            CompleteTrackDIO completeTrackDIO = BeanMapper.map(trackWorkDRO, CompleteTrackDIO.class);
            completeTrackDIO.setOperator(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM));
            completeTrackDIO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
            completeTrackDIO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
            ResponseDTO responseDTO = trackWorkModifyRemoteService.completeTrack(completeTrackDIO);
            if (!responseDTO.isSuccess()) {
                logger.info("师傅审核订单取消 完结跟单-处理失败，入参：{}，出参：{}", JSON.toJSONString(completeTrackDIO), JSON.toJSONString(responseDTO));
            }
        } else if (Objects.equals(cancelConfirmDTO.getType(), GlobalConsts.NO)) {
            // 用户不修了,直接取消订单
            this.engineerAssentCancel(cancelConfirmDTO, trackWorkDRO);
        }
    }

    /**
     * 师傅同意取消
     *
     * @param cancelConfirmDTO
     * @param trackWorkDRO
     */
    private void engineerAssentCancel(CancelConfirmDTO cancelConfirmDTO, TrackWorkDRO trackWorkDRO) throws OmsBaseException {
        ZsCancelDTO zsCancelDTO = new ZsCancelDTO();
        zsCancelDTO.setOrderId(cancelConfirmDTO.getOrderId());
        zsCancelDTO.setWorkId(cancelConfirmDTO.getWorkId());
        List<OrderRemarkDetailDTO> detailDTOList = Lists.newArrayList();
        OrderRemarkDetailDTO dto = new OrderRemarkDetailDTO();
        dto.setMapId(trackWorkDRO.getReasonId());
        dto.setMapName(trackWorkDRO.getReasonName());
        detailDTOList.add(dto);
        zsCancelDTO.setDetailDTOList(detailDTOList);
        zsCancelDTO.setOperator(cancelConfirmDTO.getOperator());
        zsCancelDTO.setOperatorType(cancelConfirmDTO.getOperatorType());
        zsCancelDTO.setOperatorId(cancelConfirmDTO.getOperatorId());
        zsCancelDTO.setAgreeCancel(GlobalConsts.YES);
        zsCancelDTO.setOperatorLogRemark("工程师同意取消");
        zsCancelDTO.setOperateTime(new Date(cancelConfirmDTO.getOperateTime().getTime() + 1));
        zsNormalWorkBService.saveCancel(zsCancelDTO);
    }

    private void insertChannelPrepaidAmountPay(OrderWork orderWork) {
        if (orderWork.getChannelPrepayAmount() == null || orderWork.getChannelPrepayAmount() <= 0) {
            return;
        }

        logger.error("系统补上渠道支付记录:{},金额:{}", orderWork.getWorkId(), orderWork.getChannelPrepayAmount());
        OrderPayResultDRO orderPayResultDRO = new OrderPayResultDRO();
        orderPayResultDRO.setPayPlat(orderWork.getPlatWork());
        orderPayResultDRO.setOrderId(orderWork.getOrderId());
        orderPayResultDRO.setWorkId(orderWork.getWorkId());
        orderPayResultDRO.setAmountType(OrderPayConsts.ORDER_PAY_CHANNEL_PREPAY);
        orderPayResultDRO.setTradeType(PayConsts.PAY_TRADE_TYPE_INTIME);
        orderPayResultDRO.setPayStatus(PayConsts.PAY_STATUS_DONE);
        orderPayResultDRO.setPayChannelId(PayConsts.PAY_CHANNEL_PLATFORM_CHANNEL);
        orderPayResultDRO.setPayType(PayConsts.PAY_TYPE_INTO);
        orderPayResultDRO.setPayTargetChannelId(0);
        orderPayResultDRO.setPayTargetType(0);
        orderPayResultDRO.setMergeInnerTradeNo("");
        orderPayResultDRO.setMergePayOutTradeNo("");
        orderPayResultDRO.setMergeAmount(0);
        orderPayResultDRO.setInnerTradeNo("");
        orderPayResultDRO.setPayOutTradeNo("");
        orderPayResultDRO.setPayTime(orderWork.getCompleteTime() != null ? orderWork.getCompleteTime() : DateUtil.getNow());
        orderPayResultDRO.setAmount(orderWork.getChannelPrepayAmount());
        orderPayResultDRO.setOperator("系统自动补偿");
        orderPayResultDRO.setOperatorId(1L);

        String lockKey = String.format("%s", orderPayResultDRO.getOrderId());
        DistributedLock lock = DistributedLockUtils.build(LockConsts.LOCK_ORDER_AMOUNT + lockKey, LockConsts.LOCK_VALID_TIME);
        try {
            if (lock.tryLock()) {
                Integer duplicationOrderPay = orderPayBService.channelPrepayAndDiscountAmountDuplicationOrderPay(orderPayResultDRO);
                if (Objects.equals(duplicationOrderPay, OrderPayConsts.ORDER_PAY_DUPLICATION_TYPE_NONE)) {
                    orderPayResultDRO.setDuplicateType(duplicationOrderPay);
                    // 插入系统自动补偿渠道预付支付记录
                    orderPayBService.insertOrderPay(orderPayResultDRO, duplicationOrderPay);
                }
                // 重复支付-业务重复
                else if (Objects.equals(duplicationOrderPay, OrderPayConsts.ORDER_PAY_DUPLICATION_TYPE_BIZ)) {
                    orderPayBService.insertOrderPay(orderPayResultDRO, duplicationOrderPay);// 插入重复支付记录
                    orderWorkAmountBService.addExceptionOrderPay(orderPayResultDRO);// 写入重复支付日志
                }
                // 重复支付-系统重复
                else {
                    logger.info("{}渠道预付系统重复或其他情况重复不处理", orderPayResultDRO.getWorkId());
                }
            }
        } catch (Exception e) {
            logger.error("insertChannelPrepaidAmountPay异常:" + e.getMessage(), e);
        } finally {
            lock.unlock();
        }
    }


    /**
     * 处理工单维修方法
     *
     * @param workDetailDTO
     */
    private void processWorkRepairMethod(WorkDetailDTO workDetailDTO) {
        if (!Objects.equals(workDetailDTO.getServItemType(), OrderConsts.SERVICE_ITEM_TYPE_QUOTATION_THREE)) {
            return;
        }

        // 查询故障维修信息
        List<OrderFault> orderFaultList = orderFaultService.listByOrderId(workDetailDTO.getOrderId());
        if (CollectionUtil.isNullOrEmpty(orderFaultList)) {
            return;
        }
        ResponseDTO<List<FaultDRO>> responseDTO = faultListRemoteService.listByIds(orderFaultList.stream().map(OrderFault::getFaultId).collect(Collectors.toList()));
        if (CollectionUtil.isNullOrEmpty(responseDTO.getData())) {
            return;
        }
        List<com.zmn.oms.common.dro.quotation3.FaultDRO> faultList = responseDTO.getData().stream().map(e -> {
            com.zmn.oms.common.dro.quotation3.FaultDRO fault = new com.zmn.oms.common.dro.quotation3.FaultDRO();
            fault.setFaultName(e.getFaultName());
            fault.setRepairMethod(e.getRepairMethod());
            return fault;
        }).collect(Collectors.toList());

        workDetailDTO.setFaultList(faultList);

    }

    private void setWorkDetailDiscountFlag(WorkDetailDTO workDetailDTO) throws OmsBaseException {
        Long orderId = workDetailDTO.getOrderId();
        Long workId = workDetailDTO.getWorkId();

        OperatePermissionVO permissionDiscount = orderWorkOperatePermissionBService.getOperatePermission(workDetailDTO.getOrderId(), workDetailDTO.getWorkId(), OrderConsts.ORDER_OP_TYPE_DISCOUNT_LEVEL_ONE);
        logger.debug("workId={} 优惠标志 出参：{}", workDetailDTO.getWorkId(), JSON.toJSONString(permissionDiscount));
        workDetailDTO.setDiscountFlag(GlobalConsts.NO);
        if (!permissionDiscount.getCanOperate()) {
            return;
        }
        if (Objects.equals(workDetailDTO.getServItemType(), OrderConsts.SERVICE_ITEM_TYPE_QUOTATION_THREE)) {
            // 3.0和一口价 判断用户是否同意维修展示优惠入口
            OrderQuotationProcess orderQuotationProcess = orderQuotationProcessService.findByOrderIdSrcMaster(orderId);
            if (Objects.nonNull(orderQuotationProcess) && Objects.equals(orderQuotationProcess.getAgreeStatus(), GlobalConsts.NO)) {
                return;
            }
            // 一口价
            if (Objects.equals(workDetailDTO.getFinalPrice(), GlobalConsts.YES)) {

                // 没有尾款 不申请优惠
                if (NumberUtil.isNullOrZero(workDetailDTO.getMasterAmount()) || workDetailDTO.getMasterAmount() < 0) {
                    return;
                }
                ArtificialPromQueryDTO artificialPromQueryDTO = ArtificialPromQueryDTO.builder().bizType(workDetailDTO.getBizType()).channelId(workDetailDTO.getChannelId()).cityId(workDetailDTO.getCityId()).orderExtendedWarranty(workDetailDTO.getMember()).plat(workDetailDTO.getPlatWork()).productId(workDetailDTO.getShowProductId()).partUse(workDetailDTO.getPartUse()).originalAmount(workDetailDTO.getOriginalAmount()).usedDiscountAmount(workDetailDTO.getDiscountAmount()).orderId(orderId).workId(workId).build();
                List<ArtificialPromDRO> artificialPromDROList = servItemBService.listArtificialProm(OrderConsts.SERVICE_ITEM_TYPE_FINAL_PRICE, artificialPromQueryDTO);
                if (CollectionUtil.isNotNullOrEmpty(artificialPromDROList)) {
                    workDetailDTO.setDiscountFlag(GlobalConsts.YES);
                } else {
                    // 获取人工优惠金额
                    List<OrderDiscount> discounts = orderDiscountService.listByOrderIdSrcMaster(orderId);
                    Integer artificialDiscountAmount = discounts.stream().filter(discount -> Objects.equals(discount.getCateg(), DiscountConsts.DISCOUNT_CATEG_ARTIFICIAL)).mapToInt(OrderDiscount::getAmount).sum();
                    if (artificialDiscountAmount > 0) {
                        // 有人工优惠的情况下 可以进入人工优惠页面
                        workDetailDTO.setDiscountFlag(GlobalConsts.YES);
                    }
                }
                return;

            } else {
                ArtificialPromQueryDTO artificialPromQueryDTO = ArtificialPromQueryDTO.builder().bizType(workDetailDTO.getBizType()).channelId(workDetailDTO.getChannelId()).cityId(workDetailDTO.getCityId()).orderExtendedWarranty(workDetailDTO.getMember()).plat(workDetailDTO.getPlatWork()).productId(workDetailDTO.getShowProductId()).build();
                List<ArtificialPromDRO> artificialPromDROList = servItemBService.listArtificialProm(OrderConsts.SERVICE_ITEM_TYPE_QUOTATION_THREE, artificialPromQueryDTO);
                if (CollectionUtil.isNotNullOrEmpty(artificialPromDROList)) {
                    workDetailDTO.setDiscountFlag(GlobalConsts.YES);
                }
            }

        } else {
            // 无后台人工优惠&非一口价，可以工程师优惠
            List<OrderDiscount> discountList = orderDiscountService.listByOrderId(orderId);
            boolean hasOperatorDiscount = discountList.stream().anyMatch(e -> (Objects.equals(e.getSourceId(), DiscountConsts.BATCH_ID_FREE_DISCOUNT_HQ_COMPANY) || Objects.equals(e.getSourceId(), DiscountConsts.BATCH_ID_FREE_DISCOUNT_SUB_COMPANY)) || (Objects.equals(e.getCateg(), DiscountConsts.DISCOUNT_CATEG_ARTIFICIAL) && Objects.equals(e.getSourceId(), DiscountConsts.BATCH_ID_ARTIFICIAL_STAFF)));
            logger.debug("workId={} 后台人工优惠:{} 优惠列表:{}", workId, hasOperatorDiscount, JSON.toJSONString(discountList));
            if (!hasOperatorDiscount) {
                PilotCheckQuery build = PilotCheckQuery.builder().channelId(workDetailDTO.getChannelId()).cityId(workDetailDTO.getCityId()).categId(workDetailDTO.getShowCategId()).servCategId(workDetailDTO.getServCategId()).pilotTypeId(PilotTypeEnum.PRICE.getId()).build();
                com.zmn.common.dto2.ResponseDTO<Boolean> supportOnePriceRemote = pilotRemoteService.checkPilotByQuery(build);
                boolean finalPrice = supportOnePriceRemote.isSuccess() && supportOnePriceRemote.getData();// 支持一口价
                if (!finalPrice) {
                    workDetailDTO.setDiscountFlag(GlobalConsts.YES);
                }
            }

        }
    }

    /**
     * 检验用户是否关注
     *
     * @param orderWork 工单信息
     */
    private Boolean checkAttentionWeChat(OrderWork orderWork) throws OmsBaseException {
        OrderThirdAppBind orderThirdAppBind = messageGetSendInfoService.getOrderWeChatBindInfoForOrderBy(orderWork.getOrderId(), orderWork.getPlatWork());
        if (Objects.isNull(orderThirdAppBind) || org.apache.commons.lang3.StringUtils.isBlank(orderThirdAppBind.getThirdAppId())) {
            return false;
        }

        ResponseDTO<Boolean> isAttentionWechat = userThirdListRemoteService.getThirdSubscribeByUserIdAndAppId(orderWork.getVisitUserId(), orderThirdAppBind.getThirdAppId());
        logger.info("订单号{},查询用户是否关注公众号,userId:{},appId:{},出参:{}", orderWork.getOrderId(), orderWork.getVisitUserId(), orderThirdAppBind.getThirdAppId(), isAttentionWechat);
        if (isAttentionWechat.isSuccess() && Objects.nonNull(isAttentionWechat.getData())) {
            return isAttentionWechat.getData();
        } else {
            logger.error("订单号{}，调用getThirdSubscribeByUserIdAndAppId查看用户是否关注公众号接口错误", orderWork.getWorkId());
            throw new OmsBaseException("查看用户是否关注公众号接口错误");
        }
    }

    /**
     * 是否可进入清洗页面
     *
     * @param orderId   订单Id
     * @param workId    订单Id
     * @param orderWork 订单
     * @return
     * @throws OmsBaseException
     */
    private Boolean enterCleanPage(Long orderId, Long workId, OrderWork orderWork) throws OmsBaseException {
        // 是否配置清洁完成照
        Boolean haveCleanPicture = false;
        OrderAttachmentQuery query = OrderAttachmentQuery.builder()
                .bizType(orderWork.getBizType())
                // 写死查询清洁服务后照片
                .categIds(Arrays.asList(171))
                .channelId(orderWork.getChannelId())
                .orderId(orderId)
                .servCategId(orderWork.getServCategId())
                .workId(workId)
                .build();
        WorkAttachmentDRO workAttachmentDRO = attachmentBService.getOrderAttachmentAndConfigByQuery(query);
        if (CollectionUtil.isNotNullOrEmpty(workAttachmentDRO.getPictureList())) {
            // 有配置照片 可以进入
            haveCleanPicture = true;
        }
        Boolean completeCleanService = false;
        MasterWorking masterWorking = masterWorkingService.findMasterWorkingByWorkId(workId);
        if (Objects.nonNull(masterWorking)) {
            completeCleanService = !masterWorking.getCompleteCleanService();
        }
        return haveCleanPicture && completeCleanService;
    }

    /**
     * 获取400 外呼号码
     * @param orderId
     * @return
     */
    private String getCalledNumber(Long orderId){
        OrderExtend orderExtend = orderExtendService.findOrderExtendByOrderId(orderId);
        String callId = orderExtend.getCallId();
        String prefix = "ti";
        String replaceCallId;
        if(!callId.contains(prefix)){
            return com.zmn.consts.GlobalConsts.SPLITER_EMPTY;
        }else{
            replaceCallId = callId.replace(prefix, GlobalConsts.SPLITER_EMPTY);
        }

        List<Long> callIds = Collections.singletonList(Long.valueOf(replaceCallId));
        logger.info("[{}]，查询通话记录入参：{}",TAG,JSON.toJSONString(callIds));
        ResponseDTO<List<CdrRecordDRO>> recordResponse = recordRemoteService.listCdrRecordsByRecordIds(callIds);
        if(!recordResponse.isSuccess()){
            logger.error("[{}]，查询通话记录请求失败，失败原因：{}",TAG,recordResponse.getMessage());

            return com.zmn.consts.GlobalConsts.SPLITER_EMPTY;
        }

        List<CdrRecordDRO> recordList = recordResponse.getData();
        logger.info("[{}]，查询通话记录返回response：{}",TAG,JSON.toJSONString(recordList));

        List<CdrRecordDRO> callTypeInList = recordList.stream()
                .filter(item -> Objects.equals(CallTypeEnum.IN.getCode(), item.getCallTypeCode()))
                .collect(Collectors.toList());

        if(CollectionUtil.isNullOrEmpty(callTypeInList)){
            return com.zmn.consts.GlobalConsts.SPLITER_EMPTY;
        }

        CdrRecordDRO cdrRecordDRO = callTypeInList.get(com.zmn.consts.GlobalConsts.NONE);
        String callee = cdrRecordDRO.getCallee();

        logger.info("[{}]，根据中继号码查询外呼号码入参：{}",TAG,callee);
        ResponseDTO<NumberDRO> trunkNumberResponse = numberListRemoteService.getNumberByTrunkNumber(callee);
        if(!trunkNumberResponse.isSuccess()){
            logger.error("[{}]，根据中继号码查询外呼号码请求失败，失败原因：{}",TAG,trunkNumberResponse.getMessage());

            return com.zmn.consts.GlobalConsts.SPLITER_EMPTY;
        }

        NumberDRO trunkData = trunkNumberResponse.getData();
        logger.info("[{}]，根据中继号码查询外呼号码返回response：{}",TAG,JSON.toJSONString(trunkData));

        return trunkData.getTelNumber();
    }


    /**
     * 获取外部店铺ID
     * @param orderId
     * @param workId
     * @return
     */
    private String getExternalShopId(Long orderId,Long workId){
        OrderExternalShop orderExternalShop = orderExternalShopService.findByOrderIdAndWorkId(orderId, workId);
        if(Objects.isNull(orderExternalShop) || StringUtil.isBlank(orderExternalShop.getExternalShopId())){
            return com.zmn.consts.GlobalConsts.SPLITER_EMPTY;
        }

        return orderExternalShop.getExternalShopId();
    }
}
